Snap for 4813226 from 87c31720385357aa1c23df4affa32aca8e234468 to pi-release
Change-Id: I02e9e1b6f15d13b74b1df3c4fa6aa6bdd6d3ba23
diff --git a/acts/framework/acts/controllers/__init__.py b/acts/framework/acts/controllers/__init__.py
index 2cc6f43..41e48df 100644
--- a/acts/framework/acts/controllers/__init__.py
+++ b/acts/framework/acts/controllers/__init__.py
@@ -25,5 +25,5 @@
"""This is a list of all the top level controller modules"""
__all__ = [
"android_device", "attenuator", "monsoon", "access_point", "iperf_server",
- "packet_sender"
+ "packet_sender", "arduino_wifi_dongle"
]
diff --git a/acts/framework/acts/controllers/arduino_wifi_dongle.py b/acts/framework/acts/controllers/arduino_wifi_dongle.py
new file mode 100644
index 0000000..7978f30
--- /dev/null
+++ b/acts/framework/acts/controllers/arduino_wifi_dongle.py
@@ -0,0 +1,392 @@
+#!/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 logging
+import os
+import re
+import serial
+import subprocess
+import threading
+import time
+
+from acts import logger
+from acts import signals
+from acts import tracelogger
+from acts import utils
+from acts.test_utils.wifi import wifi_test_utils as wutils
+
+from datetime import datetime
+
+ACTS_CONTROLLER_CONFIG_NAME = "ArduinoWifiDongle"
+ACTS_CONTROLLER_REFERENCE_NAME = "arduino_wifi_dongles"
+
+WIFI_DONGLE_EMPTY_CONFIG_MSG = "Configuration is empty, abort!"
+WIFI_DONGLE_NOT_LIST_CONFIG_MSG = "Configuration should be a list, abort!"
+
+DEV = "/dev/"
+IP = "IP: "
+STATUS = "STATUS: "
+SSID = "SSID: "
+RSSI = "RSSI: "
+PING = "PING: "
+SCAN_BEGIN = "Scan Begin"
+SCAN_END = "Scan End"
+READ_TIMEOUT = 10
+BAUD_RATE = 9600
+TMP_DIR = "tmp/"
+SSID_KEY = wutils.WifiEnums.SSID_KEY
+PWD_KEY = wutils.WifiEnums.PWD_KEY
+
+
+class ArduinoWifiDongleError(signals.ControllerError):
+ pass
+
+class DoesNotExistError(ArduinoWifiDongleError):
+ """Raised when something that does not exist is referenced."""
+
+def create(configs):
+ """Creates ArduinoWifiDongle objects.
+
+ Args:
+ configs: A list of dicts or a list of serial numbers, each representing
+ a configuration of a arduino wifi dongle.
+
+ Returns:
+ A list of Wifi dongle objects.
+ """
+ wcs = []
+ if not configs:
+ raise ArduinoWifiDongleError(WIFI_DONGLE_EMPTY_CONFIG_MSG)
+ elif not isinstance(configs, list):
+ raise ArduinoWifiDongleError(WIFI_DONGLE_NOT_LIST_CONFIG_MSG)
+ elif isinstance(configs[0], str):
+ # Configs is a list of serials.
+ wcs = get_instances(configs)
+ else:
+ # Configs is a list of dicts.
+ wcs = get_instances_with_configs(configs)
+
+ return wcs
+
+def destroy(wcs):
+ for wc in wcs:
+ wc.clean_up()
+
+def get_instances(configs):
+ wcs = []
+ for s in configs:
+ wcs.append(ArduinoWifiDongle(s))
+ return wcs
+
+def get_instances_with_configs(configs):
+ wcs = []
+ for c in configs:
+ try:
+ s = c.pop("serial")
+ except KeyError:
+ raise ArduinoWifiDongleError(
+ "'serial' is missing for ArduinoWifiDongle config %s." % c)
+ wcs.append(ArduinoWifiDongle(s))
+ return wcs
+
+class ArduinoWifiDongle(object):
+ """Class representing an arduino wifi dongle.
+
+ Each object of this class represents one wifi dongle in ACTS.
+
+ Attribtues:
+ serial: Short serial number of the wifi dongle in string.
+ port: The terminal port the dongle is connected to in string.
+ log: A logger adapted from root logger with added token specific to an
+ ArduinoWifiDongle instance.
+ log_file_fd: File handle of the log file.
+ set_logging: Logging for the dongle is enabled when this param is set
+ lock: Lock to acquire and release set_logging variable
+ ssid: SSID of the wifi network the dongle is connected to.
+ ip_addr: IP address on the wifi interface.
+ scan_results: Most recent scan results.
+ ping: Ping status in bool - ping to www.google.com
+ """
+ def __init__(self, serial=''):
+ """Initializes the ArduinoWifiDongle object."""
+ self.serial = serial
+ self.port = self._get_serial_port()
+ self.log = logger.create_tagged_trace_logger(
+ "ArduinoWifiDongle|%s" % self.serial)
+ log_path_base = getattr(logging, "log_path", "/tmp/logs")
+ self.log_file_path = os.path.join(
+ log_path_base, "ArduinoWifiDongle_%s_serial_log.txt" % self.serial)
+ self.log_file_fd = open(self.log_file_path, "a")
+
+ self.set_logging = True
+ self.lock = threading.Lock()
+ self.start_controller_log()
+
+ self.ssid = None
+ self.ip_addr = None
+ self.status = 0
+ self.scan_results = []
+ self.scanning = False
+ self.ping = False
+
+ try:
+ os.stat(TMP_DIR)
+ except:
+ os.mkdir(TMP_DIR)
+
+ def clean_up(self):
+ """Cleans up the ArduinoifiDongle object and releases any resources it
+ claimed.
+ """
+ self.stop_controller_log()
+ self.log_file_fd.close()
+
+ def _get_serial_port(self):
+ """Get the serial port for a given ArduinoWifiDongle serial number.
+
+ Returns:
+ Serial port in string if the dongle is attached.
+ """
+ if not self.serial:
+ raise ArduinoWifiDongleError(
+ "Wifi dongle's serial should not be empty")
+ cmd = "ls %s" % DEV
+ serial_ports = utils.exe_cmd(cmd).decode("utf-8", "ignore").split("\n")
+ for port in serial_ports:
+ if "USB" not in port:
+ continue
+ tty_port = "%s%s" % (DEV, port)
+ cmd = "udevadm info %s" % tty_port
+ udev_output = utils.exe_cmd(cmd).decode("utf-8", "ignore")
+ result = re.search("ID_SERIAL_SHORT=(.*)\n", udev_output)
+ if self.serial == result.group(1):
+ logging.info("Found wifi dongle %s at serial port %s" %
+ (self.serial, tty_port))
+ return tty_port
+ raise ArduinoWifiDongleError("Wifi dongle %s is specified in config"
+ " but is not attached." % self.serial)
+
+ def write(self, arduino, file_path, network=None):
+ """Write an ino file to the arduino wifi dongle.
+
+ Args:
+ arduino: path of the arduino executable.
+ file_path: path of the ino file to flash onto the dongle.
+ network: wifi network to connect to.
+
+ Returns:
+ True: if the write is sucessful.
+ False: if not.
+ """
+ return_result = True
+ self.stop_controller_log("Flashing %s\n" % file_path)
+ cmd = arduino + file_path + " --upload --port " + self.port
+ if network:
+ cmd = self._update_ino_wifi_network(arduino, file_path, network)
+ self.log.info("Command is %s" % cmd)
+ proc = subprocess.Popen(cmd,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
+ out, err = proc.communicate()
+ return_code = proc.returncode
+ if return_code != 0:
+ self.log.error("Failed to write file %s" % return_code)
+ return_result = False
+ self.start_controller_log("Flashing complete\n")
+ return return_result
+
+ def _update_ino_wifi_network(self, arduino, file_path, network):
+ """Update wifi network in the ino file.
+
+ Args:
+ arduino: path of the arduino executable.
+ file_path: path of the ino file to flash onto the dongle
+ network: wifi network to update the ino file with
+
+ Returns:
+ cmd: arduino command to run to flash the ino file
+ """
+ tmp_file = "%s%s" % (TMP_DIR, file_path.split('/')[-1])
+ utils.exe_cmd("cp %s %s" % (file_path, tmp_file))
+ ssid = network[SSID_KEY]
+ pwd = network[PWD_KEY]
+ sed_cmd = "sed -i 's/\"wifi_tethering_test\"/\"%s\"/' %s" % (ssid, tmp_file)
+ utils.exe_cmd(sed_cmd)
+ sed_cmd = "sed -i 's/\"password\"/\"%s\"/' %s" % (pwd, tmp_file)
+ utils.exe_cmd(sed_cmd)
+ cmd = "%s %s --upload --port %s" %(arduino, tmp_file, self.port)
+ return cmd
+
+ def start_controller_log(self, msg=None):
+ """Reads the serial port and writes the data to ACTS log file.
+
+ This method depends on the logging enabled in the .ino files. The logs
+ are read from the serial port and are written to the ACTS log after
+ adding a timestamp to the data.
+
+ Args:
+ msg: Optional param to write to the log file.
+ """
+ if msg:
+ curr_time = str(datetime.now())
+ self.log_file_fd.write(curr_time + " INFO: " + msg)
+ t = threading.Thread(target=self._start_log)
+ t.daemon = True
+ t.start()
+
+ def stop_controller_log(self, msg=None):
+ """Stop the controller log.
+
+ Args:
+ msg: Optional param to write to the log file.
+ """
+ with self.lock:
+ self.set_logging = False
+ if msg:
+ curr_time = str(datetime.now())
+ self.log_file_fd.write(curr_time + " INFO: " + msg)
+
+ def _start_log(self):
+ """Target method called by start_controller_log().
+
+ This method is called as a daemon thread, which continously reads the
+ serial port. Stops when set_logging is set to False or when the test
+ ends.
+ """
+ self.set_logging = True
+ ser = serial.Serial(self.port, BAUD_RATE)
+ while True:
+ curr_time = str(datetime.now())
+ data = ser.readline().decode("utf-8", "ignore")
+ self._set_vars(data)
+ with self.lock:
+ if not self.set_logging:
+ break
+ self.log_file_fd.write(curr_time + " " + data)
+
+ def _set_vars(self, data):
+ """Sets the variables by reading from the serial port.
+
+ Wifi dongle data such as wifi status, ip address, scan results
+ are read from the serial port and saved inside the class.
+
+ Args:
+ data: New line from the serial port.
+ """
+ # 'data' represents each line retrieved from the device's serial port.
+ # since we depend on the serial port logs to get the attributes of the
+ # dongle, every line has the format of {ino_file: method: param: value}.
+ # We look for the attribute in the log and retrieve its value.
+ # Ex: data = "connect_wifi: loop(): STATUS: 3" then val = "3"
+ # Similarly, we check when the scan has begun and ended and get all the
+ # scan results in between.
+ if data.count(":") != 3:
+ return
+ val = data.split(":")[-1].lstrip().rstrip()
+ if SCAN_BEGIN in data:
+ self.scan_results = []
+ self.scanning = True
+ elif SCAN_END in data:
+ self.scanning = False
+ elif self.scanning:
+ self.scan_results.append(data)
+ elif IP in data:
+ self.ip_addr = None if val == "0.0.0.0" else val
+ elif SSID in data:
+ self.ssid = val
+ elif STATUS in data:
+ self.status = int(val)
+ elif PING in data:
+ self.ping = False if int(val) == 0 else True
+
+ def ip_address(self, exp_result=True, timeout=READ_TIMEOUT):
+ """Get the ip address of the wifi dongle.
+
+ Args:
+ exp_result: True if IP address is expected (wifi connected).
+ timeout: Optional param that specifies the wait time for the IP
+ address to come up on the dongle.
+
+ Returns:
+ IP: addr in string, if wifi connected.
+ None if not connected.
+ """
+ curr_time = time.time()
+ while time.time() < curr_time + timeout:
+ if (exp_result and self.ip_addr) or \
+ (not exp_result and not self.ip_addr):
+ break
+ time.sleep(1)
+ return self.ip_addr
+
+ def wifi_status(self, exp_result=True, timeout=READ_TIMEOUT):
+ """Get wifi status on the dongle.
+
+ Returns:
+ True: if wifi is connected.
+ False: if not connected.
+ """
+ curr_time = time.time()
+ while time.time() < curr_time + timeout:
+ if (exp_result and self.status == 3) or \
+ (not exp_result and not self.status):
+ break
+ time.sleep(1)
+ return self.status == 3
+
+ def wifi_scan(self, exp_result=True, timeout=READ_TIMEOUT):
+ """Get the wifi scan results.
+
+ Args:
+ exp_result: True if scan results are expected.
+ timeout: Optional param that specifies the wait time for the scan
+ results to come up on the dongle.
+
+ Returns:
+ list of dictionaries each with SSID and RSSI of the network
+ found in the scan.
+ """
+ scan_networks = []
+ d = {}
+ curr_time = time.time()
+ while time.time() < curr_time + timeout:
+ if (exp_result and self.scan_results) or \
+ (not exp_result and not self.scan_results):
+ break
+ time.sleep(1)
+ for i in range(len(self.scan_results)):
+ if SSID in self.scan_results[i]:
+ d = {}
+ d[SSID] = self.scan_results[i].split(":")[-1].rstrip()
+ elif RSSI in self.scan_results[i]:
+ d[RSSI] = self.scan_results[i].split(":")[-1].rstrip()
+ scan_networks.append(d)
+
+ return scan_networks
+
+ def ping_status(self, exp_result=True, timeout=READ_TIMEOUT):
+ """ Get ping status on the dongle.
+
+ Returns:
+ True: if ping is successful
+ False: if not successful
+ """
+ curr_time = time.time()
+ while time.time() < curr_time + timeout:
+ if (exp_result and self.ping) or \
+ (not exp_result and not self.ping):
+ break
+ time.sleep(1)
+ return self.ping
diff --git a/acts/framework/acts/keys.py b/acts/framework/acts/keys.py
index 526ef71..a0aa52a 100644
--- a/acts/framework/acts/keys.py
+++ b/acts/framework/acts/keys.py
@@ -47,6 +47,7 @@
key_packet_sender = "PacketSender"
key_monsoon = "Monsoon"
key_sniffer = "Sniffer"
+ key_arduino_wifi_dongle = "ArduinoWifiDongle"
# Internal keys, used internally, not exposed to user's config files.
ikey_user_param = "user_params"
ikey_testbed_name = "testbed_name"
@@ -64,6 +65,7 @@
m_key_iperf_server = "iperf_server"
m_key_packet_sender = "packet_sender"
m_key_sniffer = "sniffer"
+ m_key_arduino_wifi_dongle = "arduino_wifi_dongle"
# A list of keys whose values in configs should not be passed to test
# classes without unpacking first.
@@ -81,6 +83,7 @@
key_monsoon,
key_sniffer,
key_chameleon_device,
+ key_arduino_wifi_dongle,
]
# Keys that are file or folder paths.
diff --git a/acts/framework/acts/logger.py b/acts/framework/acts/logger.py
index 92f1e5e..2f94f83 100755
--- a/acts/framework/acts/logger.py
+++ b/acts/framework/acts/logger.py
@@ -255,3 +255,17 @@
>>> lambda log_message: return 'string'
"""
return tracelogger.TraceLogger(LoggerAdapter(logging_lambda))
+
+
+def create_tagged_trace_logger(tag=''):
+ """Returns a logger that logs each line with the given prefix.
+
+ Args:
+ tag: The tag of the log line, E.g. if tag == tag123, the output
+ line would be:
+
+ <TESTBED> <TIME> <LOG_LEVEL> [tag123] logged message
+ """
+ def logging_lambda(msg):
+ return '[%s] %s' % (tag, msg)
+ return create_logger(logging_lambda)
diff --git a/acts/framework/acts/test_utils/net/arduino_test_utils.py b/acts/framework/acts/test_utils/net/arduino_test_utils.py
new file mode 100644
index 0000000..af0b3da
--- /dev/null
+++ b/acts/framework/acts/test_utils/net/arduino_test_utils.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python3.4
+#
+# Copyright 2018 Google, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import logging
+import time
+import pprint
+
+from enum import IntEnum
+from queue import Empty
+
+from acts import asserts
+from acts import signals
+from acts import utils
+from acts.controllers import attenuator
+from acts.test_utils.wifi import wifi_constants
+from acts.test_utils.tel import tel_defines
+from acts.test_utils.wifi import wifi_test_utils as wutils
+
+ARDUINO = "/root/arduino/arduino-1.8.5/arduino "
+CONNECT_WIFI = "/arduino/connect_wifi/connect_wifi.ino"
+DISCONNECT_WIFI = "/arduino/disconnect_wifi/disconnect_wifi.ino"
+SSID = wutils.WifiEnums.SSID_KEY
+PWD = wutils.WifiEnums.PWD_KEY
+
+def connect_wifi(wd, network=None):
+ """Connect wifi on arduino wifi dongle
+
+ Args:
+ wd - wifi dongle object
+ network - wifi network to connect to
+ """
+ wd.log.info("Flashing connect_wifi.ino onto dongle")
+ cmd = "locate %s" % CONNECT_WIFI
+ file_path = utils.exe_cmd(cmd).decode("utf-8", "ignore").rstrip()
+ write_status = wd.write(ARDUINO, file_path, network)
+ asserts.assert_true(write_status, "Failed to flash connect wifi")
+ wd.log.info("Flashing complete")
+ wifi_status = wd.wifi_status()
+ asserts.assert_true(wifi_status, "Failed to connect to %s" % network)
+ ping_status = wd.ping_status()
+ asserts.assert_true(ping_status, "Failed to connect to internet")
+
+def disconnect_wifi(wd):
+ """Disconnect wifi on arduino wifi dongle
+
+ Args:
+ wd - wifi dongle object
+
+ Returns:
+ True - if wifi is disconnected
+ False - if not
+ """
+ wd.log.info("Flashing disconnect_wifi.ino onto dongle")
+ cmd = "locate %s" % DISCONNECT_WIFI
+ file_path = utils.exe_cmd(cmd).decode("utf-8", "ignore").rstrip()
+ write_status = wd.write(ARDUINO, file_path)
+ asserts.assert_true(write_status, "Failed to flash disconnect wifi")
+ wd.log.info("Flashing complete")
+ wifi_status = wd.wifi_status(False)
+ asserts.assert_true(not wifi_status, "Failed to disconnect wifi")
diff --git a/acts/framework/acts/test_utils/net/connectivity_const.py b/acts/framework/acts/test_utils/net/connectivity_const.py
index 64bd8b0..bea0060 100644
--- a/acts/framework/acts/test_utils/net/connectivity_const.py
+++ b/acts/framework/acts/test_utils/net/connectivity_const.py
@@ -63,6 +63,24 @@
MULTIPATH_PREFERENCE_RELIABILITY = 1 << 1
MULTIPATH_PREFERENCE_PERFORMANCE = 1 << 2
+# IpSec constants
+SOCK_STREAM = 1
+SOCK_DGRAM = 2
+AF_INET = 2
+AF_INET6 = 10
+DIRECTION_IN = 0
+DIRECTION_OUT = 1
+MODE_TRANSPORT = 0
+MODE_TUNNEL = 1
+CRYPT_NULL = "ecb(cipher_null)"
+CRYPT_AES_CBC = "cbc(aes)"
+AUTH_HMAC_MD5 = "hmac(md5)"
+AUTH_HMAC_SHA1 = "hmac(sha1)"
+AUTH_HMAC_SHA256 = "hmac(sha256)"
+AUTH_HMAC_SHA384 = "hmac(sha384)"
+AUTH_HMAC_SHA512 = "hmac(sha512)"
+AUTH_CRYPT_AES_GCM = "rfc4106(gcm(aes))"
+
# Constants for VpnProfile
class VpnProfile(object):
""" This class contains all the possible
diff --git a/acts/framework/acts/test_utils/net/socket_test_utils.py b/acts/framework/acts/test_utils/net/socket_test_utils.py
new file mode 100644
index 0000000..a8a05fc
--- /dev/null
+++ b/acts/framework/acts/test_utils/net/socket_test_utils.py
@@ -0,0 +1,285 @@
+#
+# 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 queue
+import re
+import threading
+import time
+
+from acts.test_utils.net import connectivity_const as cconst
+from acts import asserts
+
+MSG = "Test message "
+PKTS = 5
+
+""" Methods for android.system.Os based sockets """
+def open_android_socket(ad, domain, sock_type, ip, port):
+ """ Open TCP or UDP using android.system.Os class
+
+ Args:
+ 1. ad - android device object
+ 2. domain - IPv4 or IPv6 type
+ 3. sock_type - UDP or TCP socket
+ 4. ip - IP addr on the device
+ 5. port - open socket on port
+
+ Returns:
+ File descriptor key
+ """
+ fd_key = ad.droid.openSocket(domain, sock_type, ip, port)
+ ad.log.info("File descriptor: %s" % fd_key)
+ asserts.assert_true(fd_key, "Failed to open socket")
+ return fd_key
+
+def close_android_socket(ad, fd_key):
+ """ Close socket
+
+ Args:
+ 1. ad - android device object
+ 2. fd_key - file descriptor key
+ """
+ status = ad.droid.closeSocket(fd_key)
+ asserts.assert_true(status, "Failed to close socket")
+
+def listen_accept_android_socket(client,
+ server,
+ client_fd,
+ server_fd,
+ server_ip,
+ server_port):
+ """ Listen, accept TCP sockets
+
+ Args:
+ 1. client : ad object for client device
+ 2. server : ad object for server device
+ 3. client_fd : client's socket handle
+ 4. server_fd : server's socket handle
+ 5. server_ip : send data to this IP
+ 6. server_port : send data to this port
+ """
+ server.droid.listenSocket(server_fd)
+ client.droid.connectSocket(client_fd, server_ip, server_port)
+ sock = server.droid.acceptSocket(server_fd)
+ asserts.assert_true(sock, "Failed to accept socket")
+ return sock
+
+def send_recv_data_android_sockets(client,
+ server,
+ client_fd,
+ server_fd,
+ server_ip,
+ server_port):
+ """ Send TCP or UDP data over android os sockets from client to server.
+ Verify that server received the data.
+
+ Args:
+ 1. client : ad object for client device
+ 2. server : ad object for server device
+ 3. client_fd : client's socket handle
+ 4. server_fd : server's socket handle
+ 5. server_ip : send data to this IP
+ 6. server_port : send data to this port
+ """
+ send_list = []
+ recv_list = []
+
+ for _ in range(1, PKTS+1):
+ msg = MSG + " %s" % _
+ send_list.append(msg)
+ client.log.info("Sending message: %s" % msg)
+ client.droid.sendDataOverSocket(server_ip, server_port, msg, client_fd)
+ recv_msg = server.droid.recvDataOverSocket(server_fd)
+ server.log.info("Received message: %s" % recv_msg)
+ recv_list.append(recv_msg)
+
+ recv_list = [x.rstrip('\x00') if x else x for x in recv_list]
+ asserts.assert_true(send_list and recv_list and send_list == recv_list,
+ "Send and recv information is incorrect")
+
+""" Methods for java.net.DatagramSocket based sockets """
+def open_datagram_socket(ad, ip, port):
+ """ Open datagram socket
+
+ Args:
+ 1. ad : android device object
+ 2. ip : IP addr on the device
+ 3. port : socket port
+
+ Returns:
+ Hash key of the datagram socket
+ """
+ socket_key = ad.droid.openDatagramSocket(ip, port)
+ ad.log.info("Datagram socket: %s" % socket_key)
+ asserts.assert_true(socket_key, "Failed to open datagram socket")
+ return socket_key
+
+def close_datagram_socket(ad, socket_key):
+ """ Close datagram socket
+
+ Args:
+ 1. socket_key : hash key of datagram socket
+ """
+ status = ad.droid.closeDatagramSocket(socket_key)
+ asserts.assert_true(status, "Failed to close datagram socket")
+
+def send_recv_data_datagram_sockets(client,
+ server,
+ client_sock,
+ server_sock,
+ server_ip,
+ server_port):
+ """ Send data over datagram socket from dut_a to dut_b.
+ Verify that dut_b received the data.
+
+ Args:
+ 1. client : ad object for client device
+ 2. server : ad object for server device
+ 3. client_sock : client's socket handle
+ 4. server_sock : server's socket handle
+ 5. server_ip : send data to this IP
+ 6. server_port : send data to this port
+ """
+ send_list = []
+ recv_list = []
+
+ for _ in range(1, PKTS+1):
+ msg = MSG + " %s" % _
+ send_list.append(msg)
+ client.log.info("Sending message: %s" % msg)
+ client.droid.sendDataOverDatagramSocket(client_sock,
+ msg,
+ server_ip,
+ server_port)
+ recv_msg = server.droid.recvDataOverDatagramSocket(server_sock)
+ server.log.info("Received message: %s" % recv_msg)
+ recv_list.append(recv_msg)
+
+ recv_list = [x.rstrip('\x00') if x else x for x in recv_list]
+ asserts.assert_true(send_list and recv_list and send_list == recv_list,
+ "Send and recv information is incorrect")
+
+""" Utils methods for java.net.Socket based sockets """
+def _accept_socket(server, server_ip, server_port, server_sock, q):
+ sock = server.droid.acceptTcpSocket(server_sock)
+ server.log.info("Server socket: %s" % sock)
+ q.put(sock)
+
+def _client_socket(client, server_ip, server_port, client_ip, client_port, q):
+ time.sleep(0.5)
+ sock = client.droid.openTcpSocket(server_ip,
+ server_port,
+ client_ip,
+ client_port)
+ client.log.info("Client socket: %s" % sock)
+ q.put(sock)
+
+def open_connect_socket(client,
+ server,
+ client_ip,
+ server_ip,
+ client_port,
+ server_port,
+ server_sock):
+ """ Open tcp socket and connect to server
+
+ Args:
+ 1. client : ad object for client device
+ 2. server : ad object for server device
+ 3. client_ip : client's socket handle
+ 4. server_ip : send data to this IP
+ 5. client_port : port on client socket
+ 6. server_port : port on server socket
+ 7. server_sock : server socket
+
+ Returns:
+ client and server socket from successful connect
+ """
+ sq = queue.Queue()
+ cq = queue.Queue()
+ s = threading.Thread(target = _accept_socket,
+ args = (server, server_ip, server_port, server_sock,
+ sq))
+ c = threading.Thread(target = _client_socket,
+ args = (client, server_ip, server_port, client_ip,
+ client_port, cq))
+ s.start()
+ c.start()
+ c.join()
+ s.join()
+
+ client_sock = cq.get()
+ server_sock = sq.get()
+ asserts.assert_true(client_sock and server_sock, "Failed to open sockets")
+
+ return client_sock, server_sock
+
+def open_server_socket(server, server_ip, server_port):
+ """ Open tcp server socket
+
+ Args:
+ 1. server : ad object for server device
+ 2. server_ip : send data to this IP
+ 3. server_port : send data to this port
+ """
+ sock = server.droid.openTcpServerSocket(server_ip, server_port)
+ server.log.info("Server Socket: %s" % sock)
+ asserts.assert_true(sock, "Failed to open server socket")
+ return sock
+
+def close_socket(ad, socket):
+ """ Close socket
+
+ Args:
+ 1. ad - android device object
+ 2. socket - socket key
+ """
+ status = ad.droid.closeTcpSocket(socket)
+ asserts.assert_true(status, "Failed to socket")
+
+def close_server_socket(ad, socket):
+ """ Close server socket
+
+ Args:
+ 1. ad - android device object
+ 2. socket - server socket key
+ """
+ status = ad.droid.closeTcpServerSocket(socket)
+ asserts.assert_true(status, "Failed to socket")
+
+def send_recv_data_sockets(client, server, client_sock, server_sock):
+ """ Send data over TCP socket from client to server.
+ Verify that server received the data
+
+ Args:
+ 1. client : ad object for client device
+ 2. server : ad object for server device
+ 3. client_sock : client's socket handle
+ 4. server_sock : server's socket handle
+ """
+ send_list = []
+ recv_list = []
+
+ for _ in range(1, PKTS+1):
+ msg = MSG + " %s" % _
+ send_list.append(msg)
+ client.log.info("Sending message: %s" % msg)
+ client.droid.sendDataOverTcpSocket(client_sock, msg)
+ recv_msg = server.droid.recvDataOverTcpSocket(server_sock)
+ server.log.info("Received message: %s" % recv_msg)
+ recv_list.append(recv_msg)
+
+ recv_list = [x.rstrip('\x00') if x else x for x in recv_list]
+ asserts.assert_true(send_list and recv_list and send_list == recv_list,
+ "Send and recv information is incorrect")
diff --git a/acts/framework/acts/test_utils/wifi/rtt/rtt_test_utils.py b/acts/framework/acts/test_utils/wifi/rtt/rtt_test_utils.py
index 29fac81..c24b406 100644
--- a/acts/framework/acts/test_utils/wifi/rtt/rtt_test_utils.py
+++ b/acts/framework/acts/test_utils/wifi/rtt/rtt_test_utils.py
@@ -143,6 +143,33 @@
return []
+def select_best_scan_results(scans, select_count, lowest_rssi=-80):
+ """Select the strongest 'select_count' scans in the input list based on
+ highest RSSI. Exclude all very weak signals, even if results in a shorter
+ list.
+
+ Args:
+ scans: List of scan results.
+ select_count: An integer specifying how many scans to return at most.
+ lowest_rssi: The lowest RSSI to accept into the output.
+ Returns: a list of the strongest 'select_count' scan results from the scans
+ list.
+ """
+ def takeRssi(element):
+ return element['level']
+
+ result = []
+ scans.sort(key=takeRssi, reverse=True)
+ for scan in scans:
+ if len(result) == select_count:
+ break
+ if scan['level'] < lowest_rssi:
+ break # rest are lower since we're sorted
+ result.append(scan)
+
+ return result
+
+
def validate_ap_result(scan_result, range_result):
"""Validate the range results:
- Successful if AP (per scan result) support 802.11mc (allowed to fail
diff --git a/acts/framework/acts/test_utils/wifi/wifi_retail_ap.py b/acts/framework/acts/test_utils/wifi/wifi_retail_ap.py
index a05eca4..f2b41ec 100644
--- a/acts/framework/acts/test_utils/wifi/wifi_retail_ap.py
+++ b/acts/framework/acts/test_utils/wifi/wifi_retail_ap.py
@@ -13,10 +13,11 @@
# 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 fcntl
+import logging
+import selenium
import splinter
import time
-from acts.libs.proc import job
-from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
BROWSER_WAIT_SHORT = 1
BROWSER_WAIT_MED = 3
@@ -52,74 +53,90 @@
return
-def start_chrome_browser(headless, max_allowed_sessions, timeout):
- """Method to start chrome browser for retail AP configuration
+class BlockingBrowser(splinter.driver.webdriver.chrome.WebDriver):
+ """Class that implements a blocking browser session on top of selenium.
- This function starts a chrome browser session to interface with the APs
- web interface. The function attempts to maintain only one chromedriver
- session by waiting until no chromedriver sessions are running on a machine.
-
- Args:
- headless: boolean controlling headless operation
- max_allowed_sessions: maximum number of concurrent chrome sessions
- timeout: maximum waiting time to launch chrome session
- Returns:
- browser: chrome browser session
- Raises:
- TimeoutError: raised when a browser session could not be started
- withing the specified timeout
+ The class inherits from and builds upon splinter/selenium's webdriver class
+ and makes sure that only one such webdriver is active on a machine at any
+ single time. The class ensures single session operation using a lock file.
+ The class is to be used within context managers (e.g. with statements) to
+ ensure locks are always properly released.
"""
- chrome_options = splinter.driver.webdriver.chrome.Options()
- chrome_options.add_argument("--no-proxy-server")
- chrome_options.add_argument("--no-sandbox")
- chrome_options.add_argument("--allow-running-insecure-content")
- chrome_options.add_argument("--ignore-certificate-errors")
- chrome_capabilities = DesiredCapabilities.CHROME.copy()
- chrome_capabilities["acceptSslCerts"] = True
- chrome_capabilities["acceptInsecureCerts"] = True
- if headless:
- chrome_options.add_argument("--headless")
- chrome_options.add_argument("--disable-gpu")
- start_time = time.time()
- end_time = start_time + timeout
- while time.time() < end_time:
- browsers_running = int(job.run('pgrep chromedriver | wc -l').stdout)
- if browsers_running >= max_allowed_sessions:
- time.sleep(BROWSER_WAIT_SHORT)
- else:
+ def __init__(self, headless, timeout):
+ """Constructor for BlockingBrowser class.
+
+ Args:
+ headless: boolean to control visible/headless browser operation
+ timeout: maximum time allowed to launch browser
+ """
+ self.chrome_options = splinter.driver.webdriver.chrome.Options()
+ self.chrome_options.add_argument("--no-proxy-server")
+ self.chrome_options.add_argument("--no-sandbox")
+ self.chrome_options.add_argument("--allow-running-insecure-content")
+ self.chrome_options.add_argument("--ignore-certificate-errors")
+ self.chrome_capabilities = selenium.webdriver.common.desired_capabilities.DesiredCapabilities.CHROME.copy(
+ )
+ self.chrome_capabilities["acceptSslCerts"] = True
+ self.chrome_capabilities["acceptInsecureCerts"] = True
+ if headless:
+ self.chrome_options.add_argument("--headless")
+ self.chrome_options.add_argument("--disable-gpu")
+ self.lock_file_path = "/usr/local/bin/chromedriver"
+ self.timeout = timeout
+
+ def __enter__(self):
+ self.lock_file = open(self.lock_file_path, "r")
+ start_time = time.time()
+ while time.time() < start_time + self.timeout:
try:
- browser = splinter.Browser(
- "chrome",
- options=chrome_options,
- desired_capabilities=chrome_capabilities)
- return browser
- except:
+ fcntl.flock(self.lock_file, fcntl.LOCK_EX | fcntl.LOCK_NB)
+ self.driver = selenium.webdriver.Chrome(
+ options=self.chrome_options,
+ desired_capabilities=self.chrome_capabilities)
+ self.element_class = splinter.driver.webdriver.WebDriverElement
+ self._cookie_manager = splinter.driver.webdriver.cookie_manager.CookieManager(
+ self.driver)
+ super(splinter.driver.webdriver.chrome.WebDriver,
+ self).__init__(2)
+ return super(BlockingBrowser, self).__enter__()
+ except BlockingIOError:
time.sleep(BROWSER_WAIT_SHORT)
- raise TimeoutError("Could not start chrome browser in time.")
+ raise TimeoutError("Could not start chrome browser in time.")
-
-def visit_config_page(browser, url, page_load_timeout, num_tries):
- """Method to visit Netgear AP webpages.
-
- This function visits a web page and checks the the resulting URL matches
- the intended URL, i.e. no redirects have happened
-
- Args:
- browser: the splinter browser object that will visit the URL
- url: the intended url
- num_tries: number of tries before url is declared unreachable
- """
- browser.driver.set_page_load_timeout(page_load_timeout)
- for idx in range(num_tries):
+ def __exit__(self, exc_type, exc_value, traceback):
try:
- browser.visit(url)
+ super(BlockingBrowser, self).__exit__(exc_type, exc_value,
+ traceback)
except:
- browser.visit("about:blank")
- if browser.url.split("/")[-1] == url.split("/")[-1]:
- break
- if idx == num_tries - 1:
- raise RuntimeError("URL was unreachable.")
+ raise RuntimeError("Failed to quit browser. Releasing lock file.")
+ finally:
+ fcntl.flock(self.lock_file, fcntl.LOCK_UN)
+ self.lock_file.close()
+
+ def visit_persistent(self, url, page_load_timeout, num_tries):
+ """Method to visit webpages and retry upon failure.
+
+ The function visits a web page and checks the the resulting URL matches
+ the intended URL, i.e. no redirects have happened
+
+ Args:
+ url: the intended url
+ page_load_timeout: timeout for page visits
+ num_tries: number of tries before url is declared unreachable
+ """
+ self.driver.set_page_load_timeout(page_load_timeout)
+ for idx in range(num_tries):
+ try:
+ self.visit(url)
+ except:
+ self.visit("about:blank")
+ if self.url.split("/")[-1] == url.split("/")[-1]:
+ break
+ if idx == num_tries - 1:
+ logging.error("URL unreachable. Current URL: {}".format(
+ self.url))
+ raise RuntimeError("URL unreachable.")
class WifiRetailAP(object):
@@ -148,6 +165,7 @@
with the assumed settings saved in the AP object. When called after AP
configuration, this method helps ensure that our configuration was
successful.
+ Note: Calling this function updates the stored ap_settings
Raises:
ValueError: If read AP settings do not match stored settings.
@@ -155,8 +173,9 @@
assumed_ap_settings = self.ap_settings.copy()
actual_ap_settings = self.read_ap_settings()
if assumed_ap_settings != actual_ap_settings:
- raise ValueError(
- "Discrepancy in AP settings. Potential configuration error.")
+ logging.warning(
+ "Discrepancy in AP settings. Some settings may have been overwritten."
+ )
def configure_ap(self):
"""Function that configures ap based on values of ap_settings.
@@ -166,6 +185,20 @@
"""
raise NotImplementedError
+ def set_region(self, region):
+ """Function that sets AP region.
+
+ This function sets the region for the AP. Note that this may overwrite
+ channel and bandwidth settings in cases where the new region does not
+ support the current wireless configuration.
+
+ Args:
+ region: string indicating AP region
+ """
+ logging.warning("Updating region may overwrite wireless settings.")
+ setting_to_update = {"region": region}
+ self.update_ap_settings(setting_to_update)
+
def set_radio_on_off(self, network, status):
"""Function that turns the radio on or off.
@@ -381,22 +414,22 @@
def read_ap_settings(self):
"""Function to read ap settings."""
- with start_chrome_browser(self.ap_settings["headless_browser"], 1,
- 600) as browser:
+ with BlockingBrowser(self.ap_settings["headless_browser"],
+ 600) as browser:
# Visit URL
- visit_config_page(browser, self.config_page, BROWSER_WAIT_MED, 10)
- visit_config_page(browser, self.config_page_nologin,
- BROWSER_WAIT_MED, 10)
+ browser.visit_persistent(self.config_page, BROWSER_WAIT_MED, 10)
+ browser.visit_persistent(self.config_page_nologin,
+ BROWSER_WAIT_MED, 10)
for key, value in self.config_page_fields.items():
if "status" in key:
- visit_config_page(browser, self.config_page_advanced,
- BROWSER_WAIT_MED, 10)
+ browser.visit_persistent(self.config_page_advanced,
+ BROWSER_WAIT_MED, 10)
config_item = browser.find_by_name(value)
self.ap_settings["{}_{}".format(key[1], key[0])] = int(
config_item.first.checked)
- visit_config_page(browser, self.config_page_nologin,
- BROWSER_WAIT_MED, 10)
+ browser.visit_persistent(self.config_page_nologin,
+ BROWSER_WAIT_MED, 10)
else:
config_item = browser.find_by_name(value)
if "bandwidth" in key:
@@ -425,12 +458,12 @@
# Turn radios on or off
self.configure_radio_on_off()
# Configure radios
- with start_chrome_browser(self.ap_settings["headless_browser"], 1,
- 600) as browser:
+ with BlockingBrowser(self.ap_settings["headless_browser"],
+ 600) as browser:
# Visit URL
- visit_config_page(browser, self.config_page, BROWSER_WAIT_MED, 10)
- visit_config_page(browser, self.config_page_nologin,
- BROWSER_WAIT_MED, 10)
+ browser.visit_persistent(self.config_page, BROWSER_WAIT_MED, 10)
+ browser.visit_persistent(self.config_page_nologin,
+ BROWSER_WAIT_MED, 10)
# Update region, and power/bandwidth for each network
for key, value in self.config_page_fields.items():
@@ -443,9 +476,13 @@
config_item.select_by_text(self.ap_settings["region"])
elif "bandwidth" in key:
config_item = browser.find_by_name(value).first
- config_item.select_by_text(
- self.bw_mode_text[self.ap_settings["{}_{}".format(
- key[1], key[0])]])
+ try:
+ config_item.select_by_text(
+ self.bw_mode_text[self.ap_settings["{}_{}".format(
+ key[1], key[0])]])
+ except AttributeError:
+ logging.warning(
+ "Cannot select bandwidth. Keeping AP default.")
# Update security settings (passwords updated only if applicable)
for key, value in self.config_page_fields.items():
@@ -472,9 +509,13 @@
key[1], key[0])])
elif "channel" in key:
config_item = browser.find_by_name(value).first
- config_item.select(self.ap_settings["{}_{}".format(
- key[1], key[0])])
- time.sleep(BROWSER_WAIT_SHORT)
+ try:
+ config_item.select(self.ap_settings["{}_{}".format(
+ key[1], key[0])])
+ time.sleep(BROWSER_WAIT_SHORT)
+ except AttributeError:
+ logging.warning(
+ "Cannot select channel. Keeping AP default.")
try:
alert = browser.get_alert()
alert.accept()
@@ -490,18 +531,17 @@
time.sleep(BROWSER_WAIT_SHORT)
except:
time.sleep(BROWSER_WAIT_SHORT)
- visit_config_page(browser, self.config_page,
- BROWSER_WAIT_EXTRA_LONG, 10)
- self.validate_ap_settings()
+ 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 start_chrome_browser(self.ap_settings["headless_browser"], 1,
- 600) as browser:
+ with BlockingBrowser(self.ap_settings["headless_browser"],
+ 600) as browser:
# Visit URL
- visit_config_page(browser, self.config_page, BROWSER_WAIT_MED, 10)
- visit_config_page(browser, self.config_page_advanced,
- BROWSER_WAIT_MED, 10)
+ 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
status_toggled = False
@@ -521,8 +561,8 @@
time.sleep(BROWSER_WAIT_SHORT)
browser.find_by_name("Apply").first.click()
time.sleep(BROWSER_WAIT_EXTRA_LONG)
- visit_config_page(browser, self.config_page,
- BROWSER_WAIT_EXTRA_LONG, 10)
+ browser.visit_persistent(self.config_page,
+ BROWSER_WAIT_EXTRA_LONG, 10)
class NetgearR7500AP(WifiRetailAP):
@@ -622,10 +662,10 @@
self.read_radio_on_off()
# Get radio configuration. Note that if both radios are off, the below
# code will result in an error
- with start_chrome_browser(self.ap_settings["headless_browser"], 1,
- 600) as browser:
- visit_config_page(browser, self.config_page, BROWSER_WAIT_MED, 10)
- visit_config_page(browser, self.config_page, BROWSER_WAIT_MED, 10)
+ with BlockingBrowser(self.ap_settings["headless_browser"],
+ 600) as browser:
+ browser.visit_persistent(self.config_page, BROWSER_WAIT_MED, 10)
+ browser.visit_persistent(self.config_page, BROWSER_WAIT_MED, 10)
time.sleep(BROWSER_WAIT_SHORT)
wireless_button = browser.find_by_id("wireless").first
wireless_button.click()
@@ -667,10 +707,10 @@
# Turn radios on or off
self.configure_radio_on_off()
# Configure radios
- with start_chrome_browser(self.ap_settings["headless_browser"], 1,
- 600) as browser:
- visit_config_page(browser, self.config_page, BROWSER_WAIT_MED, 10)
- visit_config_page(browser, self.config_page, BROWSER_WAIT_MED, 10)
+ with BlockingBrowser(self.ap_settings["headless_browser"],
+ 600) as browser:
+ browser.visit_persistent(self.config_page, BROWSER_WAIT_MED, 10)
+ browser.visit_persistent(self.config_page, BROWSER_WAIT_MED, 10)
time.sleep(BROWSER_WAIT_SHORT)
wireless_button = browser.find_by_id("wireless").first
wireless_button.click()
@@ -696,18 +736,29 @@
48 < int(self.ap_settings["{}_{}".format(
key[1], key[0])]) < 149)
config_item = iframe.find_by_name(value).first
- config_item.select_by_text(channel_string)
+ try:
+ config_item.select_by_text(channel_string)
+ except AttributeError:
+ logging.warning(
+ "Cannot select channel. Keeping AP default.")
elif key == ("2G", "bandwidth"):
config_item = iframe.find_by_name(value).first
- config_item.select_by_text(
- str(self.bw_mode_text_2g[self.ap_settings[
- "{}_{}".format(key[1], key[0])]]))
+ try:
+ config_item.select_by_text(
+ str(self.bw_mode_text_2g[self.ap_settings[
+ "{}_{}".format(key[1], key[0])]]))
+ except AttributeError:
+ logging.warning(
+ "Cannot select bandwidth. Keeping AP default.")
elif key == ("5G_1", "bandwidth"):
config_item = iframe.find_by_name(value).first
- config_item.select_by_text(
- str(self.bw_mode_text_5g[self.ap_settings[
- "{}_{}".format(key[1], key[0])]]))
-
+ try:
+ config_item.select_by_text(
+ str(self.bw_mode_text_5g[self.ap_settings[
+ "{}_{}".format(key[1], key[0])]]))
+ except AttributeError:
+ logging.warning(
+ "Cannot select bandwidth. Keeping AP default.")
# Update passwords for WPA2-PSK protected networks
# (Must be done after security type is selected)
for key, value in self.config_page_fields.items():
@@ -738,17 +789,16 @@
pass
time.sleep(BROWSER_WAIT_SHORT)
time.sleep(BROWSER_WAIT_EXTRA_LONG)
- visit_config_page(browser, self.config_page,
- BROWSER_WAIT_EXTRA_LONG, 10)
- self.validate_ap_settings()
+ 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 start_chrome_browser(self.ap_settings["headless_browser"], 1,
- 600) as browser:
- visit_config_page(browser, self.config_page, BROWSER_WAIT_MED, 10)
- visit_config_page(browser, self.config_page_advanced,
- BROWSER_WAIT_MED, 10)
+ with BlockingBrowser(self.ap_settings["headless_browser"],
+ 600) as browser:
+ browser.visit_persistent(self.config_page, BROWSER_WAIT_MED, 10)
+ browser.visit_persistent(self.config_page_advanced,
+ BROWSER_WAIT_MED, 10)
time.sleep(BROWSER_WAIT_SHORT)
wireless_button = browser.find_by_id("advanced_bt").first
wireless_button.click()
@@ -777,16 +827,16 @@
time.sleep(BROWSER_WAIT_SHORT)
browser.find_by_name("Apply").first.click()
time.sleep(BROWSER_WAIT_EXTRA_LONG)
- visit_config_page(browser, self.config_page,
- BROWSER_WAIT_EXTRA_LONG, 10)
+ browser.visit_persistent(self.config_page,
+ BROWSER_WAIT_EXTRA_LONG, 10)
def read_radio_on_off(self):
"""Helper configuration function to read radio status."""
- with start_chrome_browser(self.ap_settings["headless_browser"], 1,
- 600) as browser:
- visit_config_page(browser, self.config_page, BROWSER_WAIT_MED, 10)
- visit_config_page(browser, self.config_page_advanced,
- BROWSER_WAIT_MED, 10)
+ with BlockingBrowser(self.ap_settings["headless_browser"],
+ 600) as browser:
+ browser.visit_persistent(self.config_page, BROWSER_WAIT_MED, 10)
+ browser.visit_persistent(self.config_page_advanced,
+ BROWSER_WAIT_MED, 10)
wireless_button = browser.find_by_id("advanced_bt").first
wireless_button.click()
time.sleep(BROWSER_WAIT_SHORT)
diff --git a/acts/tests/google/net/arduino/connect_wifi/connect_wifi.ino b/acts/tests/google/net/arduino/connect_wifi/connect_wifi.ino
new file mode 100644
index 0000000..14bd196
--- /dev/null
+++ b/acts/tests/google/net/arduino/connect_wifi/connect_wifi.ino
@@ -0,0 +1,93 @@
+#include <ESP8266WiFi.h>
+#include <ESP8266Ping.h>
+#include <WiFiUdp.h>
+
+const char* ssid = "wifi_tethering_test";
+const char* password = "password";
+
+unsigned int localPort = 8888;
+char packetBuffer[UDP_TX_PACKET_MAX_SIZE];
+WiFiUDP Udp;
+
+
+void setup() {
+ delay(1000); // wait for a second to read from serial port after flashing
+ Serial.begin(9600);
+ Serial.println("connect: setup(): CALL: Setup Begin");
+ Serial.println("connect: setup(): INFO: Setting baud rate to 9600");
+
+ wifiStatus();
+ connectWifi();
+
+ Udp.begin(localPort);
+ Serial.println("connect: setup(): CALL: Setup End");
+}
+
+void loop() {
+ wifiStatus();
+ udpPackets();
+}
+
+void connectWifi() {
+ Serial.println("connect: connectWifi(): CALL: Connect Begin");
+ WiFi.begin(ssid, password);
+ while (WiFi.status() != WL_CONNECTED) {
+ Serial.println("connect: setup(): INFO: WiFi disconnected");
+ delay(1000);
+ }
+ Serial.println("connect: connectWifi(): CALL: Connect End");
+}
+
+void wifiStatus() {
+ Serial.println("connect: wifiStatus(): CALL: Status Begin");
+ Serial.println("connect: wifiStatus(): INFO: WiFi connected");
+ Serial.print("connect: wifiStatus(): STATUS: ");
+ Serial.println(WiFi.status());
+ Serial.print("connect: wifiStatus(): IP: ");
+ Serial.println(WiFi.localIP());
+ Serial.print("connect: wifiStatus(): SSID: ");
+ Serial.println(WiFi.SSID());
+ bool ret = Ping.ping("www.google.com", 3);
+ Serial.print("connect: wifiStatus(): PING: ");
+ if (ret) {
+ Serial.println("1");
+ } else {
+ Serial.println("0");
+ }
+
+ delay(250);
+ Serial.println("connect: wifiStatus(): CALL: Status End");
+}
+
+void udpPackets() {
+ Serial.println("connect: udpPackets(): CALL: UDP Begin");
+ int packetSize = Udp.parsePacket();
+ while(packetSize) {
+ Serial.print("connect: udpPackets(): PKTSZ: ");
+ Serial.println(packetSize);
+ Serial.print("connect: udpPackets(): REMOTEIP: ");
+ IPAddress remote = Udp.remoteIP();
+ for (int i =0; i < 4; i++) {
+ Serial.print(remote[i], DEC);
+ if (i < 3) {
+ Serial.print(".");
+ }
+ }
+ Serial.println("");
+ Serial.print("connect: udpPackets(): REMOTEPORT: ");
+ Serial.println(Udp.remotePort());
+
+ // read the packet into packetBufffer
+ Udp.read(packetBuffer,UDP_TX_PACKET_MAX_SIZE);
+ Serial.print("connect: udpPackets(): RECV: ");
+ Serial.println(packetBuffer);
+
+ // send the same message back
+ Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
+ Udp.write(packetBuffer);
+ Udp.endPacket();
+
+ packetSize = Udp.parsePacket();
+ }
+ Serial.println("connect: udpPackets(): CALL: UDP End");
+}
diff --git a/acts/tests/google/net/arduino/disconnect_wifi/disconnect_wifi.ino b/acts/tests/google/net/arduino/disconnect_wifi/disconnect_wifi.ino
new file mode 100644
index 0000000..cacef95
--- /dev/null
+++ b/acts/tests/google/net/arduino/disconnect_wifi/disconnect_wifi.ino
@@ -0,0 +1,64 @@
+#include <ESP8266WiFi.h>
+
+void setup() {
+ delay(1000); // wait for a second to read from serial port after flashing
+ Serial.begin(9600);
+ Serial.println("disconnect: setup(): CALL: Setup Begin");
+ Serial.println("disconnect: setup(): INFO: Setting baud rate to 9600");
+
+ wifiStatus();
+ disconnectWifi();
+
+ Serial.println("disconnect: setup(): CALL: Setup End");
+}
+
+void loop() {
+ wifiStatus();
+ scanNetworks();
+}
+
+void disconnectWifi() {
+ Serial.println("disconnect: setup(): CALL: Disconnect Begin");
+ WiFi.disconnect();
+ while (WiFi.status() == WL_CONNECTED) {
+ Serial.println("disconnect: setup(): INFO: WiFi connected");
+ delay(1000);
+ }
+ Serial.println("disconnect: setup(): CALL: Disconnect End");
+}
+
+void wifiStatus() {
+ Serial.println("disconnect: wifiStatus(): CALL: Status Begin");
+ Serial.println("disconnect: loop(): INFO: WiFi disconnected");
+ Serial.print("disconnect: wifiStatus(): STATUS: ");
+ Serial.println(WiFi.status());
+ Serial.print("disconnect: wifiStatus(): IP: ");
+ Serial.println(WiFi.localIP());
+ Serial.print("disconnect: wifiStatus(): SSID: ");
+ Serial.println(WiFi.SSID());
+ delay(1000);
+ Serial.println("disconnect: wifiStatus(): CALL: Status End");
+}
+
+void scanNetworks() {
+ Serial.println("disconnect: scanNetworks(): CALL: Scan Begin");
+ int n = WiFi.scanNetworks();
+ if (n == 0) {
+ Serial.println("disconnect: scanNetworks(): INFO: No networks found");
+ Serial.println("disconnect: scanNetworks(): COUNT: 0");
+ } else {
+ Serial.println("disconnect: scanNetworks(): INFO: WiFi Networks Found");
+ Serial.print("COUNT: ");
+ Serial.println(n);
+
+ for (int i = 0; i < n; ++i) {
+ Serial.print("SSID: ");
+ Serial.println(WiFi.SSID(i));
+ Serial.print("RSSI: ");
+ Serial.println(WiFi.RSSI(i));
+ }
+ }
+
+ delay(5000); // Wait a bit before scanning again
+ Serial.println("disconnect: scanNetworks(): CALL: Scan End");
+}
diff --git a/acts/tests/google/wifi/WifiRvrTest.py b/acts/tests/google/wifi/WifiRvrTest.py
index b0b2298..34a32c7 100644
--- a/acts/tests/google/wifi/WifiRvrTest.py
+++ b/acts/tests/google/wifi/WifiRvrTest.py
@@ -343,6 +343,11 @@
rvr_result = {}
# Configure AP
band = self.access_point.band_lookup_by_channel(channel)
+ if wutils.WifiEnums.channel_5G_to_freq[
+ channel] 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, channel)
self.access_point.set_bandwidth(band, mode)
self.log.info("Access Point Configuration: {}".format(
@@ -469,6 +474,118 @@
def test_rvr_TCP_UL_ch48_VHT20(self):
self._test_rvr()
+ @test_tracker_info(uuid='c2e199ce-d23f-4a24-b146-74e762085620')
+ def test_rvr_TCP_DL_ch52_VHT20(self):
+ self._test_rvr()
+
+ @test_tracker_info(uuid='5c5943e8-9d91-4270-a5ab-e7018807c64e')
+ def test_rvr_TCP_UL_ch52_VHT20(self):
+ self._test_rvr()
+
+ @test_tracker_info(uuid='b52afe89-182f-4bad-8879-cbf7001d28ef')
+ def test_rvr_TCP_DL_ch56_VHT20(self):
+ self._test_rvr()
+
+ @test_tracker_info(uuid='f8526241-3b96-463a-9082-a749a8650d5f')
+ def test_rvr_TCP_UL_ch56_VHT20(self):
+ self._test_rvr()
+
+ @test_tracker_info(uuid='c3042d7e-7468-4ab8-aec3-9b3088ba3e4c')
+ def test_rvr_TCP_DL_ch60_VHT20(self):
+ self._test_rvr()
+
+ @test_tracker_info(uuid='80426542-b035-4fb3-9010-e997f95d4964')
+ def test_rvr_TCP_UL_ch60_VHT20(self):
+ self._test_rvr()
+
+ @test_tracker_info(uuid='aa0e7117-390c-4265-adf2-0990f65f8b0b')
+ def test_rvr_TCP_DL_ch64_VHT20(self):
+ self._test_rvr()
+
+ @test_tracker_info(uuid='b2fdda85-256b-4368-8e8b-39274062264e')
+ def test_rvr_TCP_UL_ch64_VHT20(self):
+ self._test_rvr()
+
+ @test_tracker_info(uuid='48b6590f-1553-4170-83a5-40d3976e9e77')
+ def test_rvr_TCP_DL_ch100_VHT20(self):
+ self._test_rvr()
+
+ @test_tracker_info(uuid='2d0525fe-57ce-49d3-826d-4ebedd2ca6d6')
+ def test_rvr_TCP_UL_ch100_VHT20(self):
+ self._test_rvr()
+
+ @test_tracker_info(uuid='52da922d-6c2f-4afa-aca3-c19438ae3217')
+ def test_rvr_TCP_DL_ch100_VHT40(self):
+ self._test_rvr()
+
+ @test_tracker_info(uuid='2c7e7106-88c8-47ba-ac28-362475abec41')
+ def test_rvr_TCP_UL_ch100_VHT40(self):
+ self._test_rvr()
+
+ @test_tracker_info(uuid='fd4a7118-e9fe-4931-b32c-f69efd3e6493')
+ def test_rvr_TCP_DL_ch100_VHT80(self):
+ self._test_rvr()
+
+ @test_tracker_info(uuid='146502b2-9cab-4bbe-8a5c-7ec625edc2ef')
+ def test_rvr_TCP_UL_ch100_VHT80(self):
+ self._test_rvr()
+
+ @test_tracker_info(uuid='a5e185d6-b523-4016-bc8a-2a32cdc67ae0')
+ def test_rvr_TCP_DL_ch104_VHT20(self):
+ self._test_rvr()
+
+ @test_tracker_info(uuid='886aed91-0fdc-432d-b47e-ebfa85ac27ad')
+ def test_rvr_TCP_UL_ch104_VHT20(self):
+ self._test_rvr()
+
+ @test_tracker_info(uuid='fda3de6e-3183-401b-b98c-1b076da139e1')
+ def test_rvr_TCP_DL_ch108_VHT20(self):
+ self._test_rvr()
+
+ @test_tracker_info(uuid='29cc30f5-bbc8-4b64-9789-a56154907af5')
+ def test_rvr_TCP_UL_ch108_VHT20(self):
+ self._test_rvr()
+
+ @test_tracker_info(uuid='5c52ccac-8c38-46fa-a7b3-d714b6a814ad')
+ def test_rvr_TCP_DL_ch112_VHT20(self):
+ self._test_rvr()
+
+ @test_tracker_info(uuid='cc1c2a0b-71a3-4343-b7ff-489527c839d2')
+ def test_rvr_TCP_UL_ch112_VHT20(self):
+ self._test_rvr()
+
+ @test_tracker_info(uuid='11c6ccc3-e347-44ce-9a79-6c90e9dfd0a0')
+ def test_rvr_TCP_DL_ch116_VHT20(self):
+ self._test_rvr()
+
+ @test_tracker_info(uuid='29f0fce1-005d-4ad7-97d7-6b43cbdff01b')
+ def test_rvr_TCP_UL_ch116_VHT20(self):
+ self._test_rvr()
+
+ @test_tracker_info(uuid='112302b1-8261-479a-b397-916b08fbbdd2')
+ def test_rvr_TCP_DL_ch132_VHT20(self):
+ self._test_rvr()
+
+ @test_tracker_info(uuid='3bb0efb8-ddfc-4a0b-b7cf-6d6af1dbb9f4')
+ def test_rvr_TCP_UL_ch132_VHT20(self):
+ self._test_rvr()
+
+ @test_tracker_info(uuid='11a4638f-d872-4730-82eb-71d9c64e0e16')
+ def test_rvr_TCP_DL_ch136_VHT20(self):
+ self._test_rvr()
+
+ @test_tracker_info(uuid='4d797c24-3bbe-43a6-ac9e-291db1aa732a')
+ def test_rvr_TCP_UL_ch136_VHT20(self):
+ self._test_rvr()
+
+ @test_tracker_info(uuid='5d433b44-0395-43cb-b85a-be138390b18b')
+ def test_rvr_TCP_DL_ch140_VHT20(self):
+ self._test_rvr()
+
+ @test_tracker_info(uuid='47061772-21b1-4330-bd4f-daec21afa0c8')
+ def test_rvr_TCP_UL_ch140_VHT20(self):
+ self._test_rvr()
+
@test_tracker_info(uuid='24aa1e7a-3978-4803-877f-3ac5812ab0ae')
def test_rvr_TCP_DL_ch149_VHT20(self):
self._test_rvr()
@@ -618,6 +735,19 @@
"test_rvr_TCP_DL_ch161_VHT20", "test_rvr_TCP_UL_ch161_VHT20")
+class WifiRvr_SampleDFS_Test(WifiRvrTest):
+ def __init__(self, controllers):
+ base_test.BaseTestClass.__init__(self, controllers)
+ self.tests = (
+ "test_rvr_TCP_DL_ch64_VHT20", "test_rvr_TCP_UL_ch64_VHT20",
+ "test_rvr_TCP_DL_ch100_VHT20", "test_rvr_TCP_UL_ch100_VHT20",
+ "test_rvr_TCP_DL_ch100_VHT40", "test_rvr_TCP_UL_ch100_VHT40",
+ "test_rvr_TCP_DL_ch100_VHT80", "test_rvr_TCP_UL_ch100_VHT80",
+ "test_rvr_TCP_DL_ch116_VHT20", "test_rvr_TCP_UL_ch116_VHT20",
+ "test_rvr_TCP_DL_ch132_VHT20", "test_rvr_TCP_UL_ch132_VHT20",
+ "test_rvr_TCP_DL_ch140_VHT20", "test_rvr_TCP_UL_ch140_VHT20")
+
+
class WifiRvr_SampleUDP_Test(WifiRvrTest):
def __init__(self, controllers):
base_test.BaseTestClass.__init__(self, controllers)
diff --git a/acts/tests/google/wifi/WifiTetheringTest.py b/acts/tests/google/wifi/WifiTetheringTest.py
index fa20aa5..080f9e4 100644
--- a/acts/tests/google/wifi/WifiTetheringTest.py
+++ b/acts/tests/google/wifi/WifiTetheringTest.py
@@ -29,6 +29,8 @@
from acts.test_utils.tel.tel_test_utils import verify_http_connection
from acts.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_2G
from acts.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_5G
+from acts.test_utils.net import socket_test_utils as sutils
+from acts.test_utils.net import arduino_test_utils as dutils
from acts.test_utils.wifi import wifi_test_utils as wutils
WAIT_TIME = 2
@@ -162,6 +164,56 @@
wutils.wifi_connect(dut, self.network)
device_connected[dut_id] = not device_connected[dut_id]
+ def _connect_disconnect_android_device(self, dut_id, wifi_state):
+ """ Connect or disconnect wifi on android device depending on the
+ current wifi state
+
+ Args:
+ 1. dut_id: tethered device to change the wifi state
+ 2. wifi_state: current wifi state
+ """
+ ad = self.tethered_devices[dut_id]
+ if wifi_state:
+ self.log.info("Disconnecting wifi on android device")
+ wutils.wifi_forget_network(ad, self.network["SSID"])
+ else:
+ self.log.info("Connecting to wifi on android device")
+ wutils.wifi_connect(ad, self.network)
+
+ def _connect_disconnect_wifi_dongle(self, dut_id, wifi_state):
+ """ Connect or disconnect wifi on wifi dongle depending on the
+ current wifi state
+
+ Args:
+ 1. dut_id: wifi dongle to change the wifi state
+ 2. wifi_state: current wifi state
+ """
+ wd = self.arduino_wifi_dongles[dut_id]
+ if wifi_state:
+ self.log.info("Disconnecting wifi on dongle")
+ dutils.disconnect_wifi(wd)
+ else:
+ self.log.info("Connecting to wifi on dongle")
+ dutils.connect_wifi(wd, self.network)
+
+ def _connect_disconnect_tethered_devices(self):
+ """ Connect disconnect tethered devices to wifi hotspot """
+ num_android_devices = len(self.tethered_devices)
+ num_wifi_dongles = 0
+ if self.arduino_wifi_dongles:
+ num_wifi_dongles = len(self.arduino_wifi_dongles)
+ total_devices = num_android_devices + num_wifi_dongles
+ device_connected = [False] * total_devices
+ for _ in range(50):
+ dut_id = random.randint(0, total_devices-1)
+ wifi_state = device_connected[dut_id]
+ if dut_id < num_android_devices:
+ self._connect_disconnect_android_device(dut_id, wifi_state)
+ else:
+ self._connect_disconnect_wifi_dongle(dut_id-num_android_devices,
+ wifi_state)
+ device_connected[dut_id] = not device_connected[dut_id]
+
def _verify_ping(self, dut, ip, isIPv6=False):
""" Verify ping works from the dut to IP/hostname
@@ -191,25 +243,24 @@
return dut.droid.connectivityGetIPv4Addresses(iface_name) + \
dut.droid.connectivityGetIPv6Addresses(iface_name)
- def _test_traffic_between_two_tethered_devices(self, dut1, dut2):
+ def _test_traffic_between_two_tethered_devices(self, ad, wd):
""" Verify pinging interfaces of one DUT from another
Args:
- 1. dut1 - tethered device 1
- 2. dut2 - tethered device 2
+ 1. ad - android device
+ 2. wd - wifi dongle
"""
- wutils.wifi_connect(dut1, self.network)
- wutils.wifi_connect(dut2, self.network)
+ wutils.wifi_connect(ad, self.network)
+ dutils.connect_wifi(wd, self.network)
+ local_ip = ad.droid.connectivityGetIPv4Addresses('wlan0')[0]
+ remote_ip = wd.ip_address()
+ port = 8888
- dut1_ipaddrs = dut1.droid.connectivityGetIPv4Addresses("wlan0") + \
- dut1.droid.connectivityGetIPv6Addresses("wlan0")
- dut2_ipaddrs = dut2.droid.connectivityGetIPv4Addresses("wlan0") + \
- dut2.droid.connectivityGetIPv6Addresses("wlan0")
-
- for ip in dut1_ipaddrs:
- asserts.assert_true(self._verify_ping(dut2, ip), "%s " % ip)
- for ip in dut2_ipaddrs:
- asserts.assert_true(self._verify_ping(dut1, ip), "%s " % ip)
+ time.sleep(6) # wait until UDP packets method is invoked
+ socket = sutils.open_datagram_socket(ad, local_ip, port)
+ sutils.send_recv_data_datagram_sockets(
+ ad, ad, socket, socket, remote_ip, port)
+ sutils.close_datagram_socket(ad, socket)
def _ping_hotspot_interfaces_from_tethered_device(self, dut):
""" Ping hotspot interfaces from tethered device
@@ -331,7 +382,7 @@
wutils.stop_wifi_tethering(self.hotspot_device)
@test_tracker_info(uuid="110b61d1-8af2-4589-8413-11beac7a3025")
- def wifi_tethering_2ghz_traffic_between_2tethered_devices(self):
+ def test_wifi_tethering_2ghz_traffic_between_2tethered_devices(self):
""" Steps:
1. Start wifi hotspot with 2G band
@@ -341,7 +392,7 @@
wutils.toggle_wifi_off_and_on(self.hotspot_device)
self._start_wifi_tethering(WIFI_CONFIG_APBAND_2G)
self._test_traffic_between_two_tethered_devices(self.tethered_devices[0],
- self.tethered_devices[1])
+ self.arduino_wifi_dongles[0])
wutils.stop_wifi_tethering(self.hotspot_device)
@test_tracker_info(uuid="953f6e2e-27bd-4b73-85a6-d2eaa4e755d5")
@@ -355,7 +406,7 @@
wutils.toggle_wifi_off_and_on(self.hotspot_device)
self._start_wifi_tethering(WIFI_CONFIG_APBAND_5G)
self._test_traffic_between_two_tethered_devices(self.tethered_devices[0],
- self.tethered_devices[1])
+ self.arduino_wifi_dongles[0])
wutils.stop_wifi_tethering(self.hotspot_device)
@test_tracker_info(uuid="d7d5aa51-682d-4882-a334-61966d93b68c")
@@ -368,7 +419,7 @@
"""
wutils.toggle_wifi_off_and_on(self.hotspot_device)
self._start_wifi_tethering(WIFI_CONFIG_APBAND_2G)
- self._connect_disconnect_devices()
+ self._connect_disconnect_tethered_devices()
wutils.stop_wifi_tethering(self.hotspot_device)
@test_tracker_info(uuid="34abd6c9-c7f1-4d89-aa2b-a66aeabed9aa")
diff --git a/acts/tests/google/wifi/rtt/functional/RangeApNonSupporting11McTest.py b/acts/tests/google/wifi/rtt/functional/RangeApNonSupporting11McTest.py
index 813102b..65b67d2 100644
--- a/acts/tests/google/wifi/rtt/functional/RangeApNonSupporting11McTest.py
+++ b/acts/tests/google/wifi/rtt/functional/RangeApNonSupporting11McTest.py
@@ -14,15 +14,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import queue
-
from acts import asserts
from acts.test_decorators import test_tracker_info
-from acts.test_utils.wifi import wifi_test_utils as wutils
+from acts.test_utils.wifi.WifiBaseTest import WifiBaseTest
from acts.test_utils.wifi.rtt import rtt_const as rconsts
from acts.test_utils.wifi.rtt import rtt_test_utils as rutils
from acts.test_utils.wifi.rtt.RttBaseTest import RttBaseTest
-from acts.test_utils.wifi.WifiBaseTest import WifiBaseTest
class RangeApNonSupporting11McTest(WifiBaseTest, RttBaseTest):
@@ -47,7 +44,8 @@
def test_rtt_non_80211mc_supporting_aps(self):
"""Scan for APs and perform RTT on non-IEEE 802.11mc supporting APs"""
dut = self.android_devices[0]
- non_rtt_aps = rutils.scan_with_rtt_support_constraint(dut, False)
+ non_rtt_aps = rutils.select_best_scan_results(
+ rutils.scan_with_rtt_support_constraint(dut, False), select_count=1)
dut.log.debug("Visible non-IEEE 802.11mc APs=%s", non_rtt_aps)
asserts.assert_true(len(non_rtt_aps) > 0, "Need at least one AP!")
events = rutils.run_ranging(dut, non_rtt_aps, self.NUM_ITER,
@@ -84,7 +82,8 @@
device not having privilege access (expect failures)."""
dut = self.android_devices[0]
rutils.config_privilege_override(dut, True)
- non_rtt_aps = rutils.scan_with_rtt_support_constraint(dut, False)
+ non_rtt_aps = rutils.select_best_scan_results(
+ rutils.scan_with_rtt_support_constraint(dut, False), select_count=1)
dut.log.debug("Visible non-IEEE 802.11mc APs=%s", non_rtt_aps)
asserts.assert_true(len(non_rtt_aps) > 0, "Need at least one AP!")
events = rutils.run_ranging(dut, non_rtt_aps, self.NUM_ITER,
@@ -114,7 +113,8 @@
that get an error result.
"""
dut = self.android_devices[0]
- non_rtt_aps = rutils.scan_with_rtt_support_constraint(dut, False)
+ non_rtt_aps = rutils.select_best_scan_results(
+ rutils.scan_with_rtt_support_constraint(dut, False), select_count=1)
dut.log.debug("Visible non-IEEE 802.11mc APs=%s", non_rtt_aps)
asserts.assert_true(len(non_rtt_aps) > 0, "Need at least one AP!")
non_rtt_aps = non_rtt_aps[0:1] # pick first
diff --git a/acts/tests/google/wifi/rtt/functional/RangeApSupporting11McTest.py b/acts/tests/google/wifi/rtt/functional/RangeApSupporting11McTest.py
index 98586cb..d889a22 100644
--- a/acts/tests/google/wifi/rtt/functional/RangeApSupporting11McTest.py
+++ b/acts/tests/google/wifi/rtt/functional/RangeApSupporting11McTest.py
@@ -42,8 +42,9 @@
def test_rtt_80211mc_supporting_aps(self):
"""Scan for APs and perform RTT only to those which support 802.11mc"""
dut = self.android_devices[0]
- rtt_supporting_aps = rutils.scan_with_rtt_support_constraint(dut, True,
- repeat=10)
+ rtt_supporting_aps = rutils.select_best_scan_results(
+ rutils.scan_with_rtt_support_constraint(dut, True, repeat=10),
+ select_count=2)
dut.log.debug("RTT Supporting APs=%s", rtt_supporting_aps)
events = rutils.run_ranging(dut, rtt_supporting_aps, self.NUM_ITER,
self.TIME_BETWEEN_ITERATIONS)
@@ -87,8 +88,9 @@
"""Scan for APs and perform RTT only to those which support 802.11mc - using
the LEGACY API!"""
dut = self.android_devices[0]
- rtt_supporting_aps = rutils.scan_with_rtt_support_constraint(dut, True,
- repeat=10)
+ rtt_supporting_aps = rutils.select_best_scan_results(
+ rutils.scan_with_rtt_support_constraint(dut, True, repeat=10),
+ select_count=2)
dut.log.debug("RTT Supporting APs=%s", rtt_supporting_aps)
rtt_configs = []
diff --git a/acts/tests/google/wifi/rtt/functional/RttDisableTest.py b/acts/tests/google/wifi/rtt/functional/RttDisableTest.py
index cb8ade3..1816cd5 100644
--- a/acts/tests/google/wifi/rtt/functional/RttDisableTest.py
+++ b/acts/tests/google/wifi/rtt/functional/RttDisableTest.py
@@ -50,7 +50,8 @@
asserts.assert_true(dut.droid.wifiIsRttAvailable(), "RTT is not available")
# scan to get some APs to be used later
- all_aps = rutils.scan_networks(dut)
+ all_aps = rutils.select_best_scan_results(rutils.scan_networks(dut),
+ select_count=1)
asserts.assert_true(len(all_aps) > 0, "Need at least one visible AP!")
# disable RTT and validate broadcast & API
diff --git a/acts/tests/google/wifi/rtt/functional/RttRequestManagementTest.py b/acts/tests/google/wifi/rtt/functional/RttRequestManagementTest.py
index 8370290..82c1058 100644
--- a/acts/tests/google/wifi/rtt/functional/RttRequestManagementTest.py
+++ b/acts/tests/google/wifi/rtt/functional/RttRequestManagementTest.py
@@ -57,7 +57,9 @@
all_uids = [1000, 20, 30] # 1000 = System Server (makes requests foreground)
some_uids = [20, 30]
- aps = rutils.scan_with_rtt_support_constraint(dut, True, repeat=10)
+ aps = rutils.select_best_scan_results(
+ rutils.scan_with_rtt_support_constraint(dut, True, repeat=10),
+ select_count=1)
dut.log.info("RTT Supporting APs=%s", aps)
asserts.assert_true(
@@ -112,7 +114,9 @@
# background uid will be throttled on the next run of this script
fake_uid = [random.randint(10, 9999)]
- aps = rutils.scan_with_rtt_support_constraint(dut, True, repeat=10)
+ aps = rutils.select_best_scan_results(
+ rutils.scan_with_rtt_support_constraint(dut, True, repeat=10),
+ select_count=1)
dut.log.info("RTT Supporting APs=%s", aps)
asserts.assert_true(