diff options
author | Girish Moturu <gmoturu@google.com> | 2018-05-30 18:32:26 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2018-05-30 18:32:26 +0000 |
commit | 3fad38709022ac57669af42d25a398ac86be7200 (patch) | |
tree | 18c21b677c991188f632d623df2559bb87169fd7 | |
parent | 0243ef1a25801f1a727c99bac55cce85cb4ce9e3 (diff) | |
parent | 7da460b214b4e4cd982b1fb944f5612c4a5eb18a (diff) | |
download | platform_tools_test_connectivity-3fad38709022ac57669af42d25a398ac86be7200.tar.gz platform_tools_test_connectivity-3fad38709022ac57669af42d25a398ac86be7200.tar.bz2 platform_tools_test_connectivity-3fad38709022ac57669af42d25a398ac86be7200.zip |
Merge "[socket_test_utils] Add test utils for socket based methods" into pi-dev
-rw-r--r-- | acts/framework/acts/controllers/__init__.py | 2 | ||||
-rw-r--r-- | acts/framework/acts/controllers/arduino_wifi_dongle.py | 392 | ||||
-rw-r--r-- | acts/framework/acts/keys.py | 3 | ||||
-rw-r--r-- | acts/framework/acts/test_utils/net/arduino_test_utils.py | 73 | ||||
-rw-r--r-- | acts/framework/acts/test_utils/net/connectivity_const.py | 18 | ||||
-rw-r--r-- | acts/framework/acts/test_utils/net/socket_test_utils.py | 285 | ||||
-rw-r--r-- | acts/tests/google/net/arduino/connect_wifi/connect_wifi.ino | 93 | ||||
-rw-r--r-- | acts/tests/google/net/arduino/disconnect_wifi/disconnect_wifi.ino | 64 | ||||
-rw-r--r-- | acts/tests/google/wifi/WifiTetheringTest.py | 89 |
9 files changed, 999 insertions, 20 deletions
diff --git a/acts/framework/acts/controllers/__init__.py b/acts/framework/acts/controllers/__init__.py index 2cc6f43fa1..41e48dfc31 100644 --- a/acts/framework/acts/controllers/__init__.py +++ b/acts/framework/acts/controllers/__init__.py @@ -25,5 +25,5 @@ def destroy(objs): """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 0000000000..7978f3034a --- /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 526ef7146d..a0aa52af46 100644 --- a/acts/framework/acts/keys.py +++ b/acts/framework/acts/keys.py @@ -47,6 +47,7 @@ class Config(enum.Enum): 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 @@ class Config(enum.Enum): 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 @@ class Config(enum.Enum): key_monsoon, key_sniffer, key_chameleon_device, + key_arduino_wifi_dongle, ] # Keys that are file or folder paths. 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 0000000000..af0b3da15f --- /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 64bd8b024a..bea006090f 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_HANDOVER = 1 << 0 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 0000000000..a8a05fc206 --- /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/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 0000000000..14bd1961b2 --- /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 0000000000..cacef95c18 --- /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/WifiTetheringTest.py b/acts/tests/google/wifi/WifiTetheringTest.py index fa20aa5cf9..080f9e47c4 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 get_operator_name 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 @@ class WifiTetheringTest(base_test.BaseTestClass): 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 @@ class WifiTetheringTest(base_test.BaseTestClass): 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) - - 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) + 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 + + 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 @@ class WifiTetheringTest(base_test.BaseTestClass): 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 @@ class WifiTetheringTest(base_test.BaseTestClass): 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 @@ class WifiTetheringTest(base_test.BaseTestClass): 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 @@ class WifiTetheringTest(base_test.BaseTestClass): """ 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") |