Merge "Turn screen off when doing pno stress test"
diff --git a/acts/framework/acts/controllers/access_point.py b/acts/framework/acts/controllers/access_point.py
index 9e87d43..ff6eb12 100755
--- a/acts/framework/acts/controllers/access_point.py
+++ b/acts/framework/acts/controllers/access_point.py
@@ -162,6 +162,7 @@
# interfaces need to be brought down as part of the AP initialization
# process, otherwise test would fail.
try:
+ self.ssh.run('stop wpasupplicant')
self.ssh.run('stop hostapd')
except job.Error:
self.log.debug('No hostapd running')
diff --git a/acts/framework/acts/controllers/android_device.py b/acts/framework/acts/controllers/android_device.py
index 7bed102..51067ca 100755
--- a/acts/framework/acts/controllers/android_device.py
+++ b/acts/framework/acts/controllers/android_device.py
@@ -72,10 +72,6 @@
"""Raised when there is an error in AndroidDevice."""
-class DoesNotExistError(AndroidDeviceError):
- """Raised when something that does not exist is referenced."""
-
-
def create(configs):
"""Creates AndroidDevice controller objects.
@@ -103,9 +99,9 @@
for ad in ads:
if not ad.is_connected():
- raise DoesNotExistError(("Android device %s is specified in config"
- " but is not attached.") % ad.serial,
- serial=ad.serial)
+ raise AndroidDeviceError(("Android device %s is specified in config"
+ " but is not attached.") % ad.serial,
+ serial=ad.serial)
_start_services_on_ads(ads)
return ads
diff --git a/acts/framework/acts/controllers/android_lib/logcat.py b/acts/framework/acts/controllers/android_lib/logcat.py
index 9a62eb8..04a787c 100644
--- a/acts/framework/acts/controllers/android_lib/logcat.py
+++ b/acts/framework/acts/controllers/android_lib/logcat.py
@@ -92,7 +92,7 @@
"""
logger = log_stream.create_logger(
'adblog_%s' % serial, base_path=base_path,
- log_styles=(LogStyles.LOG_DEBUG | LogStyles.MONOLITH_LOG))
+ log_styles=(LogStyles.LOG_DEBUG | LogStyles.TESTCASE_LOG))
process = Process(('adb -s %s logcat -T 1 -v year %s' %
(serial, extra_params)).split(' '))
timestamp_tracker = TimestampTracker()
diff --git a/acts/framework/acts/controllers/anritsu_lib/md8475a.py b/acts/framework/acts/controllers/anritsu_lib/md8475a.py
index ea3c93f..4def316 100644
--- a/acts/framework/acts/controllers/anritsu_lib/md8475a.py
+++ b/acts/framework/acts/controllers/anritsu_lib/md8475a.py
@@ -3234,8 +3234,7 @@
except:
raise ValueError(
'The parameter slot has to be a tuple containing two ints '
- 'indicating (dl,ul) slots.'
- )
+ 'indicating (dl,ul) slots.')
# Validate
if dl < 1 or ul < 1 or dl + ul > 5:
diff --git a/acts/framework/acts/controllers/arduino_wifi_dongle.py b/acts/framework/acts/controllers/arduino_wifi_dongle.py
index 7978f30..290466a 100644
--- a/acts/framework/acts/controllers/arduino_wifi_dongle.py
+++ b/acts/framework/acts/controllers/arduino_wifi_dongle.py
@@ -17,36 +17,35 @@
import logging
import os
import re
-import serial
import subprocess
import threading
import time
+from datetime import datetime
+
+from serial import Serial
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'
-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!'
-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"
+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/"
+TMP_DIR = 'tmp/'
SSID_KEY = wutils.WifiEnums.SSID_KEY
PWD_KEY = wutils.WifiEnums.PWD_KEY
@@ -54,8 +53,6 @@
class ArduinoWifiDongleError(signals.ControllerError):
pass
-class DoesNotExistError(ArduinoWifiDongleError):
- """Raised when something that does not exist is referenced."""
def create(configs):
"""Creates ArduinoWifiDongle objects.
@@ -67,41 +64,42 @@
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)
+ return get_instances(configs)
else:
# Configs is a list of dicts.
- wcs = get_instances_with_configs(configs)
+ return 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")
+ s = c.pop('serial')
except KeyError:
raise ArduinoWifiDongleError(
- "'serial' is missing for ArduinoWifiDongle config %s." % c)
+ '"serial" is missing for ArduinoWifiDongle config %s.' % c)
wcs.append(ArduinoWifiDongle(s))
return wcs
+
class ArduinoWifiDongle(object):
"""Class representing an arduino wifi dongle.
@@ -120,16 +118,24 @@
scan_results: Most recent scan results.
ping: Ping status in bool - ping to www.google.com
"""
- def __init__(self, serial=''):
- """Initializes the ArduinoWifiDongle object."""
+
+ def __init__(self, serial):
+ """Initializes the ArduinoWifiDongle object.
+
+ Args:
+ serial: The serial number for the wifi dongle.
+ """
+ if not serial:
+ raise ArduinoWifiDongleError(
+ 'The ArduinoWifiDongle serial number must not be empty.')
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")
+ '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")
+ 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()
@@ -142,15 +148,10 @@
self.scanning = False
self.ping = False
- try:
- os.stat(TMP_DIR)
- except:
- os.mkdir(TMP_DIR)
+ os.makedirs(TMP_DIR, exist_ok=True)
def clean_up(self):
- """Cleans up the ArduinoifiDongle object and releases any resources it
- claimed.
- """
+ """Cleans up the controller and releases any resources it claimed."""
self.stop_controller_log()
self.log_file_fd.close()
@@ -160,24 +161,21 @@
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")
+ 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:
+ 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)
+ 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" %
+ 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)
+ 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.
@@ -192,19 +190,20 @@
False: if not.
"""
return_result = True
- self.stop_controller_log("Flashing %s\n" % file_path)
- cmd = arduino + file_path + " --upload --port " + self.port
+ 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)
+ self.log.info('Command is %s' % cmd)
proc = subprocess.Popen(cmd,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
- out, err = proc.communicate()
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+ shell=True)
+ _, _ = proc.communicate()
return_code = proc.returncode
if return_code != 0:
- self.log.error("Failed to write file %s" % return_code)
+ self.log.error('Failed to write file %s' % return_code)
return_result = False
- self.start_controller_log("Flashing complete\n")
+ self.start_controller_log('Flashing complete\n')
return return_result
def _update_ino_wifi_network(self, arduino, file_path, network):
@@ -216,17 +215,18 @@
network: wifi network to update the ino file with
Returns:
- cmd: arduino command to run to flash the ino file
+ 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))
+ 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)
+ 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)
+ 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)
+ cmd = "%s %s --upload --port %s" % (arduino, tmp_file, self.port)
return cmd
def start_controller_log(self, msg=None):
@@ -241,7 +241,7 @@
"""
if msg:
curr_time = str(datetime.now())
- self.log_file_fd.write(curr_time + " INFO: " + msg)
+ self.log_file_fd.write(curr_time + ' INFO: ' + msg)
t = threading.Thread(target=self._start_log)
t.daemon = True
t.start()
@@ -256,20 +256,20 @@
self.set_logging = False
if msg:
curr_time = str(datetime.now())
- self.log_file_fd.write(curr_time + " INFO: " + msg)
+ 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
+ This method is called as a daemon thread, which continuously 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)
+ ser = Serial(self.port, BAUD_RATE)
while True:
curr_time = str(datetime.now())
- data = ser.readline().decode("utf-8", "ignore")
+ data = ser.readline().decode('utf-8', 'ignore')
self._set_vars(data)
with self.lock:
if not self.set_logging:
@@ -292,9 +292,9 @@
# 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:
+ if data.count(':') != 3:
return
- val = data.split(":")[-1].lstrip().rstrip()
+ val = data.split(':')[-1].lstrip().rstrip()
if SCAN_BEGIN in data:
self.scan_results = []
self.scanning = True
@@ -303,13 +303,13 @@
elif self.scanning:
self.scan_results.append(data)
elif IP in data:
- self.ip_addr = None if val == "0.0.0.0" else val
+ 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
+ self.ping = int(val) != 0
def ip_address(self, exp_result=True, timeout=READ_TIMEOUT):
"""Get the ip address of the wifi dongle.
@@ -325,9 +325,9 @@
"""
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
+ if (exp_result and self.ip_addr) or (
+ not exp_result and not self.ip_addr):
+ break
time.sleep(1)
return self.ip_addr
@@ -340,9 +340,9 @@
"""
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
+ if (exp_result and self.status == 3) or (
+ not exp_result and not self.status):
+ break
time.sleep(1)
return self.status == 3
@@ -362,16 +362,16 @@
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
+ 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()
+ d.clear()
+ 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()
+ d[RSSI] = self.scan_results[i].split(':')[-1].rstrip()
scan_networks.append(d)
return scan_networks
@@ -385,8 +385,7 @@
"""
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
+ 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/controllers/packet_capture.py b/acts/framework/acts/controllers/packet_capture.py
index 3947bda..caf70b7 100755
--- a/acts/framework/acts/controllers/packet_capture.py
+++ b/acts/framework/acts/controllers/packet_capture.py
@@ -18,8 +18,12 @@
from acts.controllers.ap_lib.hostapd_constants import AP_DEFAULT_CHANNEL_2G
from acts.controllers.ap_lib.hostapd_constants import AP_DEFAULT_CHANNEL_5G
from acts.controllers.utils_lib.ssh import connection
+from acts.controllers.utils_lib.ssh import formatter
from acts.controllers.utils_lib.ssh import settings
+from acts.libs.logging import log_stream
+from acts.libs.proc.process import Process
+import logging
import os
import threading
import time
@@ -44,10 +48,12 @@
def create(configs):
return [PacketCapture(c) for c in configs]
+
def destroy(pcaps):
for pcap in pcaps:
pcap.close()
+
def get_info(pcaps):
return [pcap.ssh_settings.hostname for pcap in pcaps]
@@ -56,17 +62,13 @@
"""Class to maintain packet capture properties after starting tcpdump.
Attributes:
- pid: proccess id of tcpdump
- pcap_dir: tmp dir location where pcap files are saved
+ proc: Process object of tcpdump
pcap_file: pcap file name
- pcap_thread: thread used to push files to logpath
"""
- def __init__(self, pid, pcap_dir, pcap_file, pcap_thread):
+ def __init__(self, proc, pcap_file):
"""Initialize object."""
- self.pid = pid
- self.pcap_dir = pcap_dir
+ self.proc = proc
self.pcap_file = pcap_file
- self.pcap_thread = pcap_thread
class PacketCaptureError(Exception):
@@ -81,8 +83,8 @@
wifi networks; 'wlan2' which is a dual band interface.
Attributes:
- pcap: dict that specifies packet capture properties for a band.
- tmp_dirs: list of tmp directories created for pcap files.
+ pcap_properties: dict that specifies packet capture properties for a
+ band.
"""
def __init__(self, configs):
"""Initialize objects.
@@ -101,7 +103,6 @@
self.pcap_properties = dict()
self._pcap_stop_lock = threading.Lock()
- self.tmp_dirs = []
def _create_interface(self, iface, mode):
"""Create interface of monitor/managed mode.
@@ -157,62 +158,6 @@
network = {}
return scan_networks
- def _check_if_tcpdump_started(self, pcap_log):
- """Check if tcpdump started.
-
- This method ensures that tcpdump has started successfully.
- We look for 'listening on' from the stdout indicating that tcpdump
- is started.
-
- Args:
- pcap_log: log file that has redirected output of starting tcpdump.
-
- Returns:
- True/False if tcpdump is started or not.
- """
- curr_time = time.time()
- timeout = 3
- find_str = 'listening on'
- while time.time() < curr_time + timeout:
- result = self.ssh.run('grep "%s" %s' % (find_str, pcap_log),
- ignore_status=True)
- if result.stdout and find_str in result.stdout:
- return True
- time.sleep(1)
- return False
-
- def _pull_pcap(self, band, pcap_file, log_path):
- """Pulls pcap files to test log path from onhub.
-
- Called by start_packet_capture(). This method moves a pcap file to log
- path once it has reached 50MB.
-
- Args:
- index: param that indicates if the tcpdump is stopped.
- pcap_file: pcap file to move.
- log_path: log path to move the pcap file to.
- """
- curr_no = 0
- while True:
- next_no = curr_no + 1
- curr_fno = '%02i' % curr_no
- next_fno = '%02i' % next_no
- curr_file = '%s%s' % (pcap_file, curr_fno)
- next_file = '%s%s' % (pcap_file, next_fno)
-
- result = self.ssh.run('ls %s' % next_file, ignore_status=True)
- if not result.stderr and next_file in result.stdout:
- self.ssh.pull_file(log_path, curr_file)
- self.ssh.run('rm -rf %s' % curr_file, ignore_status=True)
- curr_no += 1
- continue
-
- with self._pcap_stop_lock:
- if band not in self.pcap_properties:
- self.ssh.pull_file(log_path, curr_file)
- break
- time.sleep(2) # wait before looking for file again
-
def get_wifi_scan_results(self):
"""Starts a wifi scan on wlan2 interface.
@@ -275,66 +220,53 @@
band = 2G starts tcpdump on 'mon0' interface.
band = 5G starts tcpdump on 'mon1' interface.
- This method splits the pcap file every 50MB for 100 files.
- Since, the size of the pcap file could become large, each split file
- is moved to log_path once a new file is generated. This ensures that
- there is no crash on the onhub router due to lack of space.
-
Args:
band: '2g' or '2G' and '5g' or '5G'.
log_path: test log path to save the pcap file.
pcap_file: name of the pcap file.
Returns:
- pid: process id of the tcpdump.
+ pcap_proc: Process object of the tcpdump.
"""
band = band.upper()
if band not in BAND_IFACE.keys() or band in self.pcap_properties:
self.log.error("Invalid band or packet capture already running")
return None
- pcap_dir = self.ssh.run('mktemp -d', ignore_status=True).stdout.rstrip()
- self.tmp_dirs.append(pcap_dir)
- pcap_file = os.path.join(pcap_dir, "%s_%s.pcap" % (pcap_file, band))
- pcap_log = os.path.join(pcap_dir, "%s.log" % pcap_file)
+ pcap_name = "%s_pcap" % band
+ pcap_file = os.path.join(log_path, pcap_name)
- cmd = 'tcpdump -i %s -W 100 -C 50 -w %s > %s 2>&1 & echo $!' % (
- BAND_IFACE[band], pcap_file, pcap_log)
- result = self.ssh.run(cmd, ignore_status=True)
- if not self._check_if_tcpdump_started(pcap_log):
- self.log.error("Failed to start packet capture")
- return None
+ pcap_logger = log_stream.create_logger(
+ pcap_name, base_path=log_path,
+ log_styles=(log_stream.LogStyles.LOG_DEBUG +
+ log_stream.LogStyles.MONOLITH_LOG))
+ pcap_logger.setLevel(logging.DEBUG)
+ cmd = formatter.SshFormatter().format_command(
+ 'tcpdump -i %s -l' %
+ (BAND_IFACE[band]), None, self.ssh_settings)
+ pcap_proc = Process(cmd)
+ pcap_proc.set_on_output_callback(lambda msg: pcap_logger.debug(msg))
+ pcap_proc.start()
- pcap_thread = threading.Thread(target=self._pull_pcap,
- args=(band, pcap_file, log_path))
- pcap_thread.start()
+ self.pcap_properties[band] = PcapProperties(pcap_proc, pcap_file)
+ return pcap_proc
- pid = int(result.stdout)
- self.pcap_properties[band] = PcapProperties(
- pid, pcap_dir, pcap_file, pcap_thread)
- return pid
-
- def stop_packet_capture(self, pid):
+ def stop_packet_capture(self, proc):
"""Stop the packet capture.
Args:
- pid: process id of tcpdump to kill.
+ proc: Process object of tcpdump to kill.
"""
for key, val in self.pcap_properties.items():
- if val.pid == pid:
+ if val.proc is proc:
break
else:
- self.log.error("Failed to stop tcpdump. Invalid PID %s" % pid)
+ self.log.error("Failed to stop tcpdump. Invalid process.")
return
- pcap_dir = val.pcap_dir
- pcap_thread = val.pcap_thread
- self.ssh.run('kill %s' % pid, ignore_status=True)
+ proc.stop()
with self._pcap_stop_lock:
del self.pcap_properties[key]
- pcap_thread.join()
- self.ssh.run('rm -rf %s' % pcap_dir, ignore_status=True)
- self.tmp_dirs.remove(pcap_dir)
def close(self):
"""Cleanup.
@@ -343,6 +275,4 @@
"""
self._cleanup_interface(MON_2G)
self._cleanup_interface(MON_5G)
- for tmp_dir in self.tmp_dirs:
- self.ssh.run('rm -rf %s' % tmp_dir, ignore_status=True)
self.ssh.close()
diff --git a/acts/framework/acts/controllers/packet_sender.py b/acts/framework/acts/controllers/packet_sender.py
index 6b3898a..a7d2f08 100644
--- a/acts/framework/acts/controllers/packet_sender.py
+++ b/acts/framework/acts/controllers/packet_sender.py
@@ -53,6 +53,14 @@
MDNS_RECURSIVE = 1
MDNS_V6_IP_DST = 'FF02::FB'
MDNS_V6_MAC_DST = '33:33:00:00:00:FB'
+ETH_TYPE_IP = 2048
+SAP_SPANNING_TREE = 0x42
+SNAP_OUI = 12
+SNAP_SSAP = 170
+SNAP_DSAP = 170
+SNAP_CTRL = 3
+LLC_XID_CONTROL = 191
+PAD_LEN_BYTES = 128
def create(configs):
@@ -281,11 +289,19 @@
else:
self.src_ipv4 = config_params['src_ipv4']
- def generate(self, ip_dst=None, hwsrc=None, hwdst=None, eth_dst=None):
+ def generate(self,
+ op=scapy.ARP.who_has,
+ ip_dst=None,
+ ip_src=None,
+ hwsrc=None,
+ hwdst=None,
+ eth_dst=None):
"""Generates a custom ARP packet.
Args:
+ op: ARP type (request or reply)
ip_dst: ARP ipv4 destination (Optional)
+ ip_src: ARP ipv4 source address (Optional)
hwsrc: ARP hardware source address (Optional)
hwdst: ARP hardware destination address (Optional)
eth_dst: Ethernet (layer 2) destination address (Optional)
@@ -294,8 +310,9 @@
hw_src = (hwsrc if hwsrc is not None else self.src_mac)
hw_dst = (hwdst if hwdst is not None else ARP_DST)
ipv4_dst = (ip_dst if ip_dst is not None else self.dst_ipv4)
+ ipv4_src = (ip_src if ip_src is not None else self.src_ipv4)
ip4 = scapy.ARP(
- pdst=ipv4_dst, psrc=self.src_ipv4, hwdst=hw_dst, hwsrc=hw_src)
+ op=op, pdst=ipv4_dst, psrc=ipv4_src, hwdst=hw_dst, hwsrc=hw_src)
# Create Ethernet layer
mac_dst = (eth_dst if eth_dst is not None else MAC_BROADCAST)
@@ -778,3 +795,118 @@
self.packet = ethernet / ip4 / udp / mDNS
return self.packet
+
+
+class Dot3Generator(object):
+ """Creates a custom 802.3 Ethernet Frame
+
+ Attributes:
+ packet: desired built custom packet
+ src_mac: MAC address (Layer 2) of the source node
+ src_ipv4: IPv4 address (Layer 3) of the source node
+ """
+
+ def __init__(self, **config_params):
+ """Initialize the class with the required network and packet params.
+
+ Args:
+ config_params: contains all the necessary packet parameters.
+ Some fields can be generated automatically. For example:
+ {'subnet_mask': '255.255.255.0',
+ 'dst_ipv4': '192.168.1.3',
+ 'src_ipv4: 'get_local', ...
+ The key can also be 'get_local' which means the code will read
+ and use the local interface parameters
+ """
+ interf = config_params['interf']
+ self.packet = None
+ self.dst_mac = config_params['dst_mac']
+ if config_params['src_mac'] == GET_FROM_LOCAL_INTERFACE:
+ self.src_mac = scapy.get_if_hwaddr(interf)
+ else:
+ self.src_mac = config_params['src_mac']
+
+ def _build_ether(self, eth_dst=None):
+ """Creates the basic frame for 802.3
+
+ Args:
+ eth_dst: Ethernet (layer 2) destination address (Optional)
+ """
+ # Overwrite standard fields if desired
+ sta_hw = (eth_dst if eth_dst is not None else self.dst_mac)
+ # Create Ethernet layer
+ dot3_base = scapy.Dot3(src=self.src_mac, dst=sta_hw)
+
+ return dot3_base
+
+ def _pad_frame(self, frame):
+ """Pads the frame with default length and values
+
+ Args:
+ frame: Ethernet (layer 2) to be padded
+ """
+ frame.len = PAD_LEN_BYTES
+ pad = scapy.Padding()
+ pad.load = '\x00' * PAD_LEN_BYTES
+ return frame / pad
+
+ def generate(self, eth_dst=None):
+ """Generates the basic 802.3 frame and adds padding
+
+ Args:
+ eth_dst: Ethernet (layer 2) destination address (Optional)
+ """
+ # Create 802.3 Base
+ ethernet = self._build_ether(eth_dst)
+
+ self.packet = self._pad_frame(ethernet)
+ return self.packet
+
+ def generate_llc(self, eth_dst=None, dsap=2, ssap=3, ctrl=LLC_XID_CONTROL):
+ """Generates the 802.3 frame with LLC and adds padding
+
+ Args:
+ eth_dst: Ethernet (layer 2) destination address (Optional)
+ dsap: Destination Service Access Point (Optional)
+ ssap: Source Service Access Point (Optional)
+ ctrl: Control (Optional)
+ """
+ # Create 802.3 Base
+ ethernet = self._build_ether(eth_dst)
+
+ # Create LLC layer
+ llc = scapy.LLC(dsap=dsap, ssap=ssap, ctrl=ctrl)
+
+ # Append and create packet
+ self.packet = self._pad_frame(ethernet / llc)
+ return self.packet
+
+ def generate_snap(self,
+ eth_dst=None,
+ dsap=SNAP_DSAP,
+ ssap=SNAP_SSAP,
+ ctrl=SNAP_CTRL,
+ oui=SNAP_OUI,
+ code=ETH_TYPE_IP):
+ """Generates the 802.3 frame with LLC and SNAP and adds padding
+
+ Args:
+ eth_dst: Ethernet (layer 2) destination address (Optional)
+ dsap: Destination Service Access Point (Optional)
+ ssap: Source Service Access Point (Optional)
+ ctrl: Control (Optional)
+ oid: Protocol Id or Org Code (Optional)
+ code: EtherType (Optional)
+ """
+ # Create 802.3 Base
+ ethernet = self._build_ether(eth_dst)
+
+ # Create 802.2 LLC header
+ llc = scapy.LLC(dsap=dsap, ssap=ssap, ctrl=ctrl)
+
+ # Create 802.3 SNAP header
+ snap = scapy.SNAP(OUI=oui, code=code)
+
+ # Append and create packet
+ self.packet = self._pad_frame(ethernet / llc / snap)
+ return self.packet
diff --git a/acts/framework/acts/libs/logging/log_stream.py b/acts/framework/acts/libs/logging/log_stream.py
index a10ffae..6fcc587 100644
--- a/acts/framework/acts/libs/logging/log_stream.py
+++ b/acts/framework/acts/libs/logging/log_stream.py
@@ -49,6 +49,8 @@
TO_ACTS_LOG = 0x1000
ROTATE_LOGS = 0x2000
+ ALL_FILE_LOGS = MONOLITH_LOG + TESTCLASS_LOG + TESTCASE_LOG
+
LEVEL_NAMES = {
LOG_DEBUG: 'debug',
LOG_INFO: 'info',
@@ -255,6 +257,7 @@
os.makedirs(self.base_path, exist_ok=True)
self.stream_format = stream_format
self.file_format = file_format
+ self._test_run_only_log_handlers = []
self._test_case_handler_descriptors = []
self._test_case_log_handlers = []
self._test_class_handler_descriptors = []
@@ -310,13 +313,16 @@
(log_location, level))
else:
levels_dict[level] |= log_location
- # Check that for a given log-level, not both TESTCLASS_LOG
- # and TESTCASE_LOG have been set.
- if not ~levels_dict[level] & (
- LogStyles.TESTCLASS_LOG | LogStyles.TESTCASE_LOG):
+ # Check that for a given log-level, not more than one
+ # of MONOLITH_LOG, TESTCLASS_LOG, TESTCASE_LOG is set.
+ locations = levels_dict[level] & LogStyles.ALL_FILE_LOGS
+ valid_locations = [
+ LogStyles.TESTCASE_LOG, LogStyles.TESTCLASS_LOG,
+ LogStyles.MONOLITH_LOG, LogStyles.NONE]
+ if locations not in valid_locations:
invalid_style_error(
- 'Both TESTCLASS_LOG and TESTCASE_LOG locations '
- 'have been set for log level %s.' % level)
+ 'More than one of MONOLITH_LOG, TESTCLASS_LOG, '
+ 'TESTCASE_LOG is set for log level %s.' % level)
if log_style & LogStyles.ALL_LEVELS == 0:
invalid_style_error('LogStyle %s needs to set a log '
'level.' % log_style)
@@ -371,18 +377,21 @@
# Handle streaming logs to log-level files
for log_level in LogStyles.LOG_LEVELS:
- if not log_style & log_level:
+ if not (log_style & log_level and
+ log_style & LogStyles.ALL_FILE_LOGS):
continue
descriptor = self.HandlerDescriptor(handler_creator, log_level,
self.name, self.file_format)
+
+ handler = descriptor.create(self.base_path)
+ self.logger.addHandler(handler)
+ if not log_style & LogStyles.MONOLITH_LOG:
+ self._test_run_only_log_handlers.append(handler)
if log_style & LogStyles.TESTCASE_LOG:
self._test_case_handler_descriptors.append(descriptor)
self._test_class_only_handler_descriptors.append(descriptor)
if log_style & LogStyles.TESTCLASS_LOG:
self._test_class_handler_descriptors.append(descriptor)
- if log_style & LogStyles.MONOLITH_LOG:
- handler = descriptor.create(self.base_path)
- self.logger.addHandler(handler)
def __remove_handler(self, handler):
"""Removes a handler from the logger, unless it's a NullHandler."""
@@ -411,7 +420,7 @@
"""Internal use only. To be called when a test case has ended."""
self.__clear_handlers(self._test_case_log_handlers)
- # Re-add handlers residing only in test class level contexts
+ # Enable handlers residing only in test class level contexts
for handler in self._test_class_only_log_handlers:
self.logger.addHandler(handler)
@@ -420,7 +429,7 @@
# Close test case handlers from previous tests.
self.__clear_handlers(self._test_case_log_handlers)
- # Remove handlers residing only in test class level contexts
+ # Disable handlers residing only in test class level contexts
for handler in self._test_class_only_log_handlers:
self.logger.removeHandler(handler)
@@ -434,12 +443,20 @@
self.__clear_handlers(self._test_class_log_handlers)
self.__clear_handlers(self._test_class_only_log_handlers)
+ # Enable handlers residing only in test run level contexts
+ for handler in self._test_run_only_log_handlers:
+ self.logger.addHandler(handler)
+
def on_test_class_begin(self, test_class_event):
"""Internal use only. To be called when a test class has begun."""
- # Close test case handlers from previous tests.
+ # Close test class handlers from previous tests.
self.__clear_handlers(self._test_class_log_handlers)
self.__clear_handlers(self._test_class_only_log_handlers)
+ # Disable handlers residing only in test run level contexts
+ for handler in self._test_run_only_log_handlers:
+ self.logger.removeHandler(handler)
+
# Create new handlers for this test class.
self.__create_handlers_from_descriptors(
self._test_class_handler_descriptors,
diff --git a/acts/framework/acts/libs/proc/process.py b/acts/framework/acts/libs/proc/process.py
index 477cfc6..82b6c8f 100644
--- a/acts/framework/acts/libs/proc/process.py
+++ b/acts/framework/acts/libs/proc/process.py
@@ -20,6 +20,10 @@
import time
+class ProcessError(Exception):
+ """Raised when invalid operations are run on a Process."""
+
+
class Process(object):
"""A Process object used to run various commands.
@@ -33,7 +37,7 @@
_on_output_callback: The callback to call when output is received.
_on_terminate_callback: The callback to call when the process terminates
without stop() being called first.
- _started: Whether or not the Process is in the running state.
+ _started: Whether or not start() was called.
_stopped: Whether or not stop() was called.
"""
@@ -52,6 +56,7 @@
self._on_output_callback = lambda *args, **kw: None
self._on_terminate_callback = lambda *args, **kw: ''
+ self._started = False
self._stopped = False
def set_on_output_callback(self, on_output_callback):
@@ -92,8 +97,10 @@
def start(self):
"""Starts the process's execution."""
+ if self._started:
+ raise ProcessError('Process has already started.')
+ self._started = True
self._process = None
- self._stopped = False
self._listening_thread = Thread(target=self._exec_loop)
self._listening_thread.start()
@@ -104,6 +111,8 @@
if time.time() > time_up_at:
raise OSError('Unable to open process!')
+ self._stopped = False
+
@staticmethod
def _get_timeout_left(timeout, start_time):
return max(.1, timeout - (time.time() - start_time))
@@ -116,36 +125,41 @@
"""
return self._process is not None and self._process.poll() is None
+ def _join_threads(self):
+ """Waits for the threads associated with the process to terminate."""
+ if self._listening_thread is not None:
+ self._listening_thread.join()
+ self._listening_thread = None
+
+ if self._redirection_thread is not None:
+ self._redirection_thread.join()
+ self._redirection_thread = None
+
def wait(self, kill_timeout=60.0):
"""Waits for the process to finish execution.
If the process has reached the kill_timeout, the process will be killed
instead.
+ Note: the on_self_terminate callback will NOT be called when calling
+ this function.
+
Args:
kill_timeout: The amount of time to wait until killing the process.
"""
- start_time = time.time()
+ if self._stopped:
+ raise ProcessError('Process is already being stopped.')
+ self._stopped = True
try:
self._process.wait(kill_timeout)
except subprocess.TimeoutExpired:
- self._stopped = True
self._process.kill()
+ finally:
+ self._join_threads()
+ self._started = False
- time_left = self._get_timeout_left(kill_timeout, start_time)
-
- if self._listening_thread is not None:
- self._listening_thread.join(timeout=time_left)
- self._listening_thread = None
-
- time_left = self._get_timeout_left(kill_timeout, start_time)
-
- if self._redirection_thread is not None:
- self._redirection_thread.join(timeout=time_left)
- self._redirection_thread = None
-
- def stop(self, timeout=60.0):
+ def stop(self):
"""Stops the process.
This command is effectively equivalent to kill, but gives time to clean
@@ -153,18 +167,8 @@
Note: the on_self_terminate callback will NOT be called when calling
this function.
-
- Args:
- timeout: The amount of time to wait for the program output to finish
- being handled.
"""
- self._stopped = True
-
- start_time = time.time()
-
- if self.is_running():
- self._process.kill()
- self.wait(self._get_timeout_left(timeout, start_time))
+ self.wait(0)
def _redirect_output(self):
"""Redirects the output from the command into the on_output_callback."""
diff --git a/acts/framework/acts/logger.py b/acts/framework/acts/logger.py
index b3b7662..eb1dda1 100755
--- a/acts/framework/acts/logger.py
+++ b/acts/framework/acts/logger.py
@@ -146,7 +146,7 @@
"""
logging.log_path = log_path
log_styles = [LogStyles.LOG_INFO + LogStyles.TO_STDOUT,
- LogStyles.DEFAULT_LEVELS + LogStyles.MONOLITH_LOG]
+ LogStyles.DEFAULT_LEVELS + LogStyles.TESTCASE_LOG]
terminal_format = log_line_format
if prefix:
terminal_format = "[{}] {}".format(prefix, log_line_format)
diff --git a/acts/framework/acts/test_utils/fuchsia/bt_test_utils.py b/acts/framework/acts/test_utils/fuchsia/bt_test_utils.py
index 1f25ccf..a19f4f7 100644
--- a/acts/framework/acts/test_utils/fuchsia/bt_test_utils.py
+++ b/acts/framework/acts/test_utils/fuchsia/bt_test_utils.py
@@ -29,7 +29,7 @@
The dictionary of device information.
"""
scan_filter = {"name_substring": search_name}
- fd.ble_lib.bleStartBleScan(scan_filter)
+ fd.gattc_lib.bleStartBleScan(scan_filter)
end_time = time.time() + timeout
found_device = None
while time.time() < end_time and not found_device:
@@ -42,7 +42,7 @@
log.info("Successfully found advertisement! name, id: {}, {}".
format(name, did))
found_device = device
- fd.ble_lib.bleStopBleScan()
+ fd.gattc_lib.bleStopBleScan()
if not found_device:
log.error("Failed to find device with name {}.".format(search_name))
return found_device
diff --git a/acts/framework/acts/test_utils/power/PowerCellularLabBaseTest.py b/acts/framework/acts/test_utils/power/PowerCellularLabBaseTest.py
index 676dafb..e3495aa 100644
--- a/acts/framework/acts/test_utils/power/PowerCellularLabBaseTest.py
+++ b/acts/framework/acts/test_utils/power/PowerCellularLabBaseTest.py
@@ -150,8 +150,12 @@
self.simulation.detach()
# Parse simulation parameters.
- # This may return false if incorrect values are passed.
- if not self.simulation.parse_parameters(self.parameters):
+ # This may throw a ValueError exception if incorrect values are passed
+ # or if required arguments are omitted.
+ try:
+ self.simulation.parse_parameters(self.parameters)
+ except ValueError as error:
+ self.log.error(str(error))
return False
# Wait for new params to settle
@@ -161,8 +165,7 @@
if not self.simulation.attach():
return False
- if not self.simulation.start_test_case():
- return False
+ self.simulation.start_test_case()
# Make the device go to sleep
self.dut.droid.goToSleepNow()
diff --git a/acts/framework/acts/test_utils/power/tel_simulations/BaseSimulation.py b/acts/framework/acts/test_utils/power/tel_simulations/BaseSimulation.py
index 70f8405..bb191a7 100644
--- a/acts/framework/acts/test_utils/power/tel_simulations/BaseSimulation.py
+++ b/acts/framework/acts/test_utils/power/tel_simulations/BaseSimulation.py
@@ -83,10 +83,11 @@
self.log.warning("The '{} 'key is not set in the testbed "
"parameters. Setting to off by default. To "
"turn calibration on, include the key with "
- "a true/false value.".format(self.KEY_CALIBRATION))
+ "a true/false value.".format(
+ self.KEY_CALIBRATION))
- self.calibration_required = test_config.get(self.KEY_CALIBRATION, False)
-
+ self.calibration_required = test_config.get(self.KEY_CALIBRATION,
+ False)
# Gets BTS1 since this sim only has 1 BTS
self.bts1 = self.anritsu.get_BTS(BtsNumber.BTS1)
@@ -187,10 +188,10 @@
# Set signal levels obtained from the test parameters
if self.sim_dl_power:
- self.set_downlink_rx_power(self.sim_dl_power)
+ self.set_downlink_rx_power(self.bts1, self.sim_dl_power)
time.sleep(2)
if self.sim_ul_power:
- self.set_uplink_tx_power(self.sim_ul_power)
+ self.set_uplink_tx_power(self.bts1, self.sim_ul_power)
time.sleep(2)
return True
@@ -236,11 +237,9 @@
Args:
parameters: list of parameters
- Returns:
- False if there was an error while parsing parameters
"""
- return True
+ pass
def consume_parameter(self, parameters, parameter_name, num_values=0):
""" Parses a parameter from a list.
@@ -270,17 +269,17 @@
for j in range(num_values + 1):
return_list.append(parameters.pop(i))
except IndexError:
- self.log.error(
+ raise ValueError(
"Parameter {} has to be followed by {} values.".format(
parameter_name, num_values))
- raise ValueError()
return return_list
- def set_downlink_rx_power(self, signal_level):
+ def set_downlink_rx_power(self, bts, signal_level):
""" Sets downlink rx power using calibration if available
Args:
+ bts: the base station in which to change the signal level
signal_level: desired downlink received power, can be either a
key value pair, an int or a float
"""
@@ -310,7 +309,7 @@
self.log.info(
"Requested phone DL Rx power of {} dBm, setting callbox Tx "
"power at {} dBm".format(power, calibrated_power))
- self.bts1.output_level = calibrated_power
+ bts.output_level = calibrated_power
time.sleep(2)
# Power has to be a natural number so calibration wont be exact.
# Inform the actual received power after rounding.
@@ -318,14 +317,15 @@
"Phone downlink received power is {0:.2f} dBm".format(
calibrated_power - self.dl_path_loss))
except TypeError:
- self.bts1.output_level = round(power)
+ bts.output_level = round(power)
self.log.info("Phone downlink received power set to {} (link is "
"uncalibrated).".format(round(power)))
- def set_uplink_tx_power(self, signal_level):
+ def set_uplink_tx_power(self, bts, signal_level):
""" Sets uplink tx power using calibration if available
Args:
+ bts: the base station in which to change the signal level
signal_level: desired uplink transmitted power, can be either a
key value pair, an int or a float
"""
@@ -353,7 +353,7 @@
self.log.info(
"Requested phone UL Tx power of {} dBm, setting callbox Rx "
"power at {} dBm".format(power, calibrated_power))
- self.bts1.input_level = calibrated_power
+ bts.input_level = calibrated_power
time.sleep(2)
# Power has to be a natural number so calibration wont be exact.
# Inform the actual transmitted power after rounding.
@@ -361,7 +361,7 @@
"Phone uplink transmitted power is {0:.2f} dBm".format(
calibrated_power + self.ul_path_loss))
except TypeError:
- self.bts1.input_level = round(power)
+ bts.input_level = round(power)
self.log.info("Phone uplink transmitted power set to {} (link is "
"uncalibrated).".format(round(power)))
@@ -437,7 +437,8 @@
cmd = 'OPERATEIPTRAFFIC START,1'
self.anritsu.send_command(cmd)
except AnritsuError as inst:
- self.log.warning("{}\n".format(inst)) # Typically RUNNING already
+ self.log.warning(
+ "{}\n".format(inst)) # Typically RUNNING already
time.sleep(4)
down_power_measured = []
@@ -456,7 +457,8 @@
cmd = 'OPERATEIPTRAFFIC STOP,1'
self.anritsu.send_command(cmd)
except AnritsuError as inst:
- self.log.warning("{}\n".format(inst)) # Typically STOPPED already
+ self.log.warning(
+ "{}\n".format(inst)) # Typically STOPPED already
time.sleep(2)
# Reset phone and bts to original settings
@@ -523,7 +525,8 @@
cmd = 'OPERATEIPTRAFFIC START,1'
self.anritsu.send_command(cmd)
except AnritsuError as inst:
- self.log.warning("{}\n".format(inst)) # Typically RUNNING already
+ self.log.warning(
+ "{}\n".format(inst)) # Typically RUNNING already
time.sleep(4)
up_power_per_chain = []
@@ -554,7 +557,8 @@
cmd = 'OPERATEIPTRAFFIC STOP,1'
self.anritsu.send_command(cmd)
except AnritsuError as inst:
- self.log.warning("{}\n".format(inst)) # Typically STOPPED already
+ self.log.warning(
+ "{}\n".format(inst)) # Typically STOPPED already
time.sleep(2)
# Reset phone and bts to original settings
@@ -650,10 +654,6 @@
""" Starts a test case in the current simulation.
Requires the phone to be attached.
-
- Returns:
- True if the case was successfully started.
-
"""
- return True
\ No newline at end of file
+ pass
diff --git a/acts/framework/acts/test_utils/power/tel_simulations/GsmSimulation.py b/acts/framework/acts/test_utils/power/tel_simulations/GsmSimulation.py
index 67fb981..16bfa8a 100644
--- a/acts/framework/acts/test_utils/power/tel_simulations/GsmSimulation.py
+++ b/acts/framework/acts/test_utils/power/tel_simulations/GsmSimulation.py
@@ -87,22 +87,18 @@
Args:
parameters: list of parameters
- Returns:
- False if there was an error while parsing the config
"""
- if not super().parse_parameters(parameters):
- return False
+ super().parse_parameters(parameters)
# Setup band
values = self.consume_parameter(parameters, self.PARAM_BAND, 1)
if not values:
- self.log.error(
+ raise ValueError(
"The test name needs to include parameter '{}' followed by "
"the required band number.".format(self.PARAM_BAND))
- return False
self.set_band(self.bts1, values[1])
@@ -115,24 +111,19 @@
elif self.consume_parameter(parameters, self.PARAM_NO_GPRS):
self.bts1.gsm_gprs_mode = BtsGprsMode.NO_GPRS
else:
- self.log.error(
+ raise ValueError(
"GPRS mode needs to be indicated in the test name with either "
"{}, {} or {}.".format(self.PARAM_GPRS, self.PARAM_EGPRS,
self.PARAM_NO_GPRS))
- return False
# Setup slot allocation
values = self.consume_parameter(parameters, self.PARAM_SLOTS, 2)
if not values:
- self.log.error(
+ raise ValueError(
"The test name needs to include parameter {} followed by two "
"int values indicating DL and UL slots.".format(
self.PARAM_SLOTS))
- return False
self.bts1.gsm_slots = (int(values[1]), int(values[2]))
-
- # No errors were found
- return True
diff --git a/acts/framework/acts/test_utils/power/tel_simulations/LteCaSimulation.py b/acts/framework/acts/test_utils/power/tel_simulations/LteCaSimulation.py
index 4e793d4..f401465 100644
--- a/acts/framework/acts/test_utils/power/tel_simulations/LteCaSimulation.py
+++ b/acts/framework/acts/test_utils/power/tel_simulations/LteCaSimulation.py
@@ -17,6 +17,7 @@
import time
from acts.controllers.anritsu_lib.md8475a import BtsNumber
+from acts.controllers.anritsu_lib.md8475a import BtsPacketRate
from acts.controllers.anritsu_lib.md8475a import TestProcedure
from acts.controllers.anritsu_lib.md8475a import TestPowerControl
from acts.controllers.anritsu_lib.md8475a import TestMeasurement
@@ -67,23 +68,19 @@
Args:
parameters: list of parameters
- Returns:
- False if there was an error while parsing the config
"""
- if not super(LteSimulation, self).parse_parameters(parameters):
- return False
+ super(LteSimulation, self).parse_parameters(parameters)
# Get the CA band configuration
values = self.consume_parameter(parameters, self.PARAM_CA, 1)
if not values:
- self.log.error(
+ raise ValueError(
"The test name needs to include parameter '{}' followed by "
"the CA configuration. For example: ca_3c7c28a".format(
self.PARAM_CA))
- return False
# Carrier aggregation configurations are indicated with the band numbers
# followed by the CA classes in a single string. For example, for 5 CA
@@ -91,10 +88,9 @@
ca_configs = re.findall(r'(\d+[abcABC])', values[1])
if not ca_configs:
- self.log.error(
+ raise ValueError(
"The CA configuration has to be indicated with one string as "
"in the following example: ca_3c7c28a".format(self.PARAM_CA))
- return False
carriers = []
bts_index = 0
@@ -108,20 +104,19 @@
ca_class = ca[-1]
if ca_class.upper() == 'B':
- self.log.error("Class B carrier aggregation is not supported.")
- return False
+ raise ValueError(
+ "Class B carrier aggregation is not supported.")
if band in carriers:
- self.log.error("Intra-band non contiguous carrier aggregation "
- "is not supported.")
- return False
+ raise ValueError(
+ "Intra-band non contiguous carrier aggregation "
+ "is not supported.")
if ca_class.upper() == 'A':
if bts_index >= len(self.bts):
- self.log.error("This callbox model doesn't allow the "
- "requested CA configuration")
- return False
+ raise ValueError("This callbox model doesn't allow the "
+ "requested CA configuration")
self.set_band_with_defaults(
self.bts[bts_index],
@@ -133,9 +128,8 @@
elif ca_class.upper() == 'C':
if bts_index + 1 >= len(self.bts):
- self.log.error("This callbox model doesn't allow the "
- "requested CA configuration")
- return False
+ raise ValueError("This callbox model doesn't allow the "
+ "requested CA configuration")
self.set_band_with_defaults(
self.bts[bts_index],
@@ -149,18 +143,16 @@
bts_index += 2
else:
- self.log.error("Invalid carrier aggregation configuration: "
- "{}{}.".format(band, ca_class))
- return False
+ raise ValueError("Invalid carrier aggregation configuration: "
+ "{}{}.".format(band, ca_class))
carriers.append(band)
# Ensure there are at least two carriers being used
self.num_carriers = bts_index
if self.num_carriers < 2:
- self.log.error("At least two carriers need to be indicated for the"
- " carrier aggregation sim.")
- return False
+ raise ValueError("At least two carriers need to be indicated for "
+ "the carrier aggregation sim.")
# Get the bw for each carrier
# This is an optional parameter, by default the maximum bandwidth for
@@ -213,17 +205,16 @@
self.num_carriers)
if not mimo_values:
- self.log.error("The test parameter '{}' has to be included in the "
- "test name followed by the MIMO mode for each "
- "carrier separated by underscores.".format(
- self.PARAM_MIMO))
- return False
+ raise ValueError(
+ "The test parameter '{}' has to be included in the "
+ "test name followed by the MIMO mode for each "
+ "carrier separated by underscores.".format(self.PARAM_MIMO))
if len(mimo_values) != self.num_carriers + 1:
- self.log.error("The test parameter '{}' has to be followed by "
- "a number of MIMO mode values equal to the number "
- "of carriers being used.".format(self.PARAM_MIMO))
- return False
+ raise ValueError(
+ "The test parameter '{}' has to be followed by "
+ "a number of MIMO mode values equal to the number "
+ "of carriers being used.".format(self.PARAM_MIMO))
for bts_index in range(self.num_carriers):
@@ -234,16 +225,15 @@
requested_mimo = mimo_mode
break
else:
- self.log.error("The mimo mode must be one of %s." %
- {elem.value
- for elem in LteSimulation.MimoMode})
- return False
+ raise ValueError(
+ "The mimo mode must be one of %s." %
+ {elem.value
+ for elem in LteSimulation.MimoMode})
if (requested_mimo == LteSimulation.MimoMode.MIMO_4x4
and self.anritsu._md8475_version == 'A'):
- self.log.error("The test requires 4x4 MIMO, but that is not "
- "supported by the MD8475A callbox.")
- return False
+ raise ValueError("The test requires 4x4 MIMO, but that is not "
+ "supported by the MD8475A callbox.")
self.set_mimo_mode(self.bts[bts_index], requested_mimo)
@@ -255,11 +245,10 @@
requested_tm = tm
break
else:
- self.log.error(
+ raise ValueError(
"The TM must be one of %s." %
{elem.value
for elem in LteSimulation.MimoMode})
- return False
else:
# Provide default values if the TM parameter is not set
if requested_mimo == LteSimulation.MimoMode.MIMO_1x1:
@@ -272,8 +261,101 @@
self.log.info("Cell {} was set to {} and {} MIMO.".format(
bts_index + 1, requested_tm.value, requested_mimo.value))
- # No errors were found
- return True
+ # Get uplink power
+
+ ul_power = self.get_uplink_power_from_parameters(parameters)
+
+ # Power is not set on the callbox until after the simulation is
+ # started. Saving this value in a variable for later
+ self.sim_ul_power = ul_power
+
+ # Get downlink power
+
+ dl_power = self.get_downlink_power_from_parameters(parameters)
+
+ # Power is not set on the callbox until after the simulation is
+ # started. Saving this value in a variable for later
+ self.sim_dl_power = dl_power
+
+ # Setup scheduling mode
+
+ values = self.consume_parameter(parameters, self.PARAM_SCHEDULING, 1)
+
+ if not values:
+ scheduling = LteSimulation.SchedulingMode.STATIC
+ self.log.warning(
+ "The test name does not include the '{}' parameter. Setting to "
+ "{} by default.".format(scheduling.value,
+ self.PARAM_SCHEDULING))
+ else:
+ for scheduling_mode in LteSimulation.SchedulingMode:
+ if values[1].upper() == scheduling_mode.value:
+ scheduling = scheduling_mode
+ break
+ else:
+ raise ValueError(
+ "The test name parameter '{}' has to be followed by one of "
+ "{}.".format(
+ self.PARAM_SCHEDULING,
+ {elem.value
+ for elem in LteSimulation.SchedulingMode}))
+
+ if scheduling == LteSimulation.SchedulingMode.STATIC:
+
+ values = self.consume_parameter(parameters, self.PARAM_PATTERN, 2)
+
+ if not values:
+ self.log.warning(
+ "The '{}' parameter was not set, using 100% RBs for both "
+ "DL and UL. To set the percentages of total RBs include "
+ "the '{}' parameter followed by two ints separated by an "
+ "underscore indicating downlink and uplink percentages."
+ .format(self.PARAM_PATTERN, self.PARAM_PATTERN))
+ dl_pattern = 100
+ ul_pattern = 100
+ else:
+ dl_pattern = int(values[1])
+ ul_pattern = int(values[2])
+
+ if (dl_pattern, ul_pattern) not in [(0, 100), (100, 0), (100,
+ 100)]:
+ raise ValueError(
+ "Only full RB allocation for DL or UL is supported in CA "
+ "sims. The allowed combinations are 100/0, 0/100 and "
+ "100/100.")
+
+ if self.dl_256_qam and bw == 1.4:
+ mcs_dl = 26
+ elif not self.dl_256_qam and self.tbs_pattern_on and bw != 1.4:
+ mcs_dl = 28
+ else:
+ mcs_dl = 27
+
+ if self.ul_64_qam:
+ mcs_ul = 28
+ else:
+ mcs_ul = 23
+
+ for bts_index in range(self.num_carriers):
+
+ dl_rbs, ul_rbs = self.allocation_percentages_to_rbs(
+ self.bts[bts_index], dl_pattern, ul_pattern)
+
+ self.set_scheduling_mode(
+ self.bts[bts_index],
+ LteSimulation.SchedulingMode.STATIC,
+ packet_rate=BtsPacketRate.LTE_MANUAL,
+ nrb_dl=dl_rbs,
+ nrb_ul=ul_rbs,
+ mcs_ul=mcs_ul,
+ mcs_dl=mcs_dl)
+
+ else:
+
+ for bts_index in range(self.num_carriers):
+
+ self.set_scheduling_mode(self.bts[bts_index],
+ LteSimulation.SchedulingMode.DYNAMIC)
def set_band_with_defaults(self, bts, band, calibrate_if_necessary=True):
""" Switches to the given band restoring default values
@@ -296,6 +378,22 @@
self.set_band(bts, band, calibrate_if_necessary=calibrate_if_necessary)
+ def set_downlink_rx_power(self, bts, rsrp):
+ """ Sets downlink rx power in RSRP using calibration for every cell
+
+ Calls the method in the parent class for each base station.
+
+ Args:
+ bts: this argument is ignored, as all the basestations need to have
+ the same downlink rx power
+ rsrp: desired rsrp, contained in a key value pair
+ """
+
+ for bts_index in range(self.num_carriers):
+ self.log.info("Setting DL power for BTS{}.".format(bts_index + 1))
+ # Use parent method to set signal level
+ super().set_downlink_rx_power(self.bts[bts_index], rsrp)
+
def start_test_case(self):
""" Attaches the phone to all the other basestations.
@@ -321,8 +419,17 @@
while self.anritsu.get_testcase_status() == "0":
retry_counter += 1
if retry_counter == 3:
- self.log.error("The test case failed to start.")
- return False
+ raise RuntimeError("The test case failed to start after {} "
+ "retries. The connection between the phone "
+ "and the basestation might be unstable."
+ .format(retry_counter))
time.sleep(10)
- return True
+ def maximum_downlink_throughput(self):
+ """ Calculates maximum downlink throughput as the sum of all the active
+ carriers.
+ """
+
+ return sum(
+ self.bts_maximum_downlink_throughtput(self.bts[bts_index])
+ for bts_index in range(self.num_carriers))
diff --git a/acts/framework/acts/test_utils/power/tel_simulations/LteSimulation.py b/acts/framework/acts/test_utils/power/tel_simulations/LteSimulation.py
index 9daa405..73a5cd0 100644
--- a/acts/framework/acts/test_utils/power/tel_simulations/LteSimulation.py
+++ b/acts/framework/acts/test_utils/power/tel_simulations/LteSimulation.py
@@ -301,22 +301,18 @@
Args:
parameters: list of parameters
- Returns:
- False if there was an error while parsing the config
"""
- if not super().parse_parameters(parameters):
- return False
+ super().parse_parameters(parameters)
# Setup band
values = self.consume_parameter(parameters, self.PARAM_BAND, 1)
if not values:
- self.log.error(
+ raise ValueError(
"The test name needs to include parameter '{}' followed by "
"the required band number.".format(self.PARAM_BAND))
- return False
band = values[1]
@@ -324,16 +320,16 @@
# Set DL/UL frame configuration
if self.get_duplex_mode(band) == self.DuplexMode.TDD:
- try:
- values = self.consume_parameter(parameters,
- self.PARAM_FRAME_CONFIG, 1)
- frame_config = int(values[1])
- except:
- self.log.error("When a TDD band is selected the frame "
- "structure has to be indicated with the '{}' "
- "parameter followed by a number from 0 to 6."
- .format(self.PARAM_FRAME_CONFIG))
- return False
+
+ values = self.consume_parameter(parameters,
+ self.PARAM_FRAME_CONFIG, 1)
+ if not values:
+ raise ValueError("When a TDD band is selected the frame "
+ "structure has to be indicated with the '{}' "
+ "parameter followed by a number from 0 to 6."
+ .format(self.PARAM_FRAME_CONFIG))
+
+ frame_config = int(values[1])
self.set_dlul_configuration(self.bts1, frame_config)
@@ -342,10 +338,10 @@
values = self.consume_parameter(parameters, self.PARAM_BW, 1)
if not values:
- self.log.error(
- "The test name needs to include parameter {} followed by an int"
- " value (to indicate 1.4 MHz use 14).".format(self.PARAM_BW))
- return False
+ raise ValueError(
+ "The test name needs to include parameter {} followed by an "
+ "int value (to indicate 1.4 MHz use 14).".format(
+ self.PARAM_BW))
bw = float(values[1])
@@ -359,25 +355,22 @@
values = self.consume_parameter(parameters, self.PARAM_MIMO, 1)
if not values:
- self.log.error(
- "The test name needs to include parameter '{}' followed by the"
- " mimo mode.".format(self.PARAM_MIMO))
- return False
+ raise ValueError(
+ "The test name needs to include parameter '{}' followed by the "
+ "mimo mode.".format(self.PARAM_MIMO))
for mimo_mode in LteSimulation.MimoMode:
if values[1] == mimo_mode.value:
self.set_mimo_mode(self.bts1, mimo_mode)
break
else:
- self.log.error("The {} parameter needs to be followed by either "
- "1x1, 2x2 or 4x4.".format(self.PARAM_MIMO))
- return False
+ raise ValueError("The {} parameter needs to be followed by either "
+ "1x1, 2x2 or 4x4.".format(self.PARAM_MIMO))
if (mimo_mode == LteSimulation.MimoMode.MIMO_4x4
and self.anritsu._md8475_version == 'A'):
- self.log.error("The test requires 4x4 MIMO, but that is not "
- "supported by the MD8475A callbox.")
- return False
+ raise ValueError("The test requires 4x4 MIMO, but that is not "
+ "supported by the MD8475A callbox.")
self.set_mimo_mode(self.bts1, mimo_mode)
@@ -386,21 +379,19 @@
values = self.consume_parameter(parameters, self.PARAM_TM, 1)
if not values:
- self.log.error(
- "The test name needs to include parameter {} followed by an int"
- " value from 1 to 4 indicating transmission mode.".format(
+ raise ValueError(
+ "The test name needs to include parameter {} followed by an "
+ "int value from 1 to 4 indicating transmission mode.".format(
self.PARAM_TM))
- return False
for tm in LteSimulation.TransmissionMode:
if values[1] == tm.value[2:]:
self.set_transmission_mode(self.bts1, tm)
break
else:
- self.log.error("The {} parameter needs to be followed by either "
- "TM1, TM2, TM3, TM4, TM7, TM8 or TM9.".format(
- self.PARAM_MIMO))
- return False
+ raise ValueError("The {} parameter needs to be followed by either "
+ "TM1, TM2, TM3, TM4, TM7, TM8 or TM9.".format(
+ self.PARAM_MIMO))
# Setup scheduling mode
@@ -416,10 +407,9 @@
elif values[1] == self.PARAM_SCHEDULING_STATIC:
scheduling = LteSimulation.SchedulingMode.STATIC
else:
- self.log.error(
+ raise ValueError(
"The test name parameter '{}' has to be followed by either "
"'dynamic' or 'static'.".format(self.PARAM_SCHEDULING))
- return False
if scheduling == LteSimulation.SchedulingMode.STATIC:
@@ -439,10 +429,9 @@
ul_pattern = int(values[2])
if not (0 <= dl_pattern <= 100 and 0 <= ul_pattern <= 100):
- self.log.error(
+ raise ValueError(
"The scheduling pattern parameters need to be two "
"positive numbers between 0 and 100.")
- return False
dl_rbs, ul_rbs = self.allocation_percentages_to_rbs(
self.bts1, dl_pattern, ul_pattern)
@@ -473,66 +462,74 @@
self.set_scheduling_mode(self.bts1,
LteSimulation.SchedulingMode.DYNAMIC)
- # Setup uplink power
+ # Get uplink power
+
+ ul_power = self.get_uplink_power_from_parameters(parameters)
+
+ # Power is not set on the callbox until after the simulation is
+ # started. Saving this value in a variable for later
+ self.sim_ul_power = ul_power
+
+ # Get downlink power
+
+ dl_power = self.get_downlink_power_from_parameters(parameters)
+
+ # Power is not set on the callbox until after the simulation is
+ # started. Saving this value in a variable for later
+ self.sim_dl_power = dl_power
+
+ def get_uplink_power_from_parameters(self, parameters):
+ """ Reads uplink power from a list of parameters. """
values = self.consume_parameter(parameters, self.PARAM_UL_PW, 1)
if not values or values[1] not in self.uplink_signal_level_dictionary:
- self.log.error(
+ raise ValueError(
"The test name needs to include parameter {} followed by one "
"the following values: {}.".format(self.PARAM_UL_PW, [
- "\n" + val
- for val in self.uplink_signal_level_dictionary.keys()
+ val for val in self.uplink_signal_level_dictionary.keys()
]))
- return False
- # Power is not set on the callbox until after the simulation is
- # started. Will save this value in a variable and use it lated
- self.sim_ul_power = self.uplink_signal_level_dictionary[values[1]]
+ return self.uplink_signal_level_dictionary[values[1]]
- # Setup downlink power
+ def get_downlink_power_from_parameters(self, parameters):
+ """ Reads downlink power from a list of parameters. """
values = self.consume_parameter(parameters, self.PARAM_DL_PW, 1)
if values:
if values[1] not in self.downlink_rsrp_dictionary:
- self.log.error("Invalid signal level value {}.".format(
+ raise ValueError("Invalid signal level value {}.".format(
values[1]))
- return False
else:
- power = self.downlink_rsrp_dictionary[values[1]]
+ return self.downlink_rsrp_dictionary[values[1]]
else:
# Use default value
power = self.downlink_rsrp_dictionary['excellent']
- self.log.error(
- "No DL signal level value was indicated in the test parameters."
- " Using default value of {} RSRP.".format(power))
+ self.log.info(
+ "No DL signal level value was indicated in the test "
+ "parameters. Using default value of {} RSRP.".format(power))
+ return power
- # Power is not set on the callbox until after the simulation is
- # started. Will save this value in a variable and use it later
- self.sim_dl_power = power
-
- # No errors were found
- return True
-
- def set_downlink_rx_power(self, rsrp):
+ def set_downlink_rx_power(self, bts, rsrp):
""" Sets downlink rx power in RSRP using calibration
Lte simulation overrides this method so that it can convert from
RSRP to total signal power transmitted from the basestation.
Args:
+ bts: the base station in which to change the signal level
rsrp: desired rsrp, contained in a key value pair
"""
- power = self.rsrp_to_signal_power(rsrp, self.bts1)
+ power = self.rsrp_to_signal_power(rsrp, bts)
self.log.info(
"Setting downlink signal level to {} RSRP ({} dBm)".format(
rsrp, power))
# Use parent method to set signal level
- super().set_downlink_rx_power(power)
+ super().set_downlink_rx_power(bts, power)
def downlink_calibration(self,
bts,
@@ -602,11 +599,24 @@
"""
- bandwidth = self.bts1.bandwidth
- rb_ratio = float(
- self.bts1.nrb_dl) / self.total_rbs_dictionary[bandwidth]
- streams = float(self.bts1.dl_antenna)
- mcs = self.bts1.lte_mcs_dl
+ return self.bts_maximum_downlink_throughtput(self.bts1)
+
+ def bts_maximum_downlink_throughtput(self, bts):
+ """ Calculates maximum achievable downlink throughput for the selected
+ basestation.
+
+ Args:
+ bts: basestation handle
+
+ Returns:
+ Maximum throughput in mbps.
+
+ """
+
+ bandwidth = bts.bandwidth
+ rb_ratio = float(bts.nrb_dl) / self.total_rbs_dictionary[bandwidth]
+ streams = float(bts.dl_antenna)
+ mcs = bts.lte_mcs_dl
max_rate_per_stream = None
@@ -673,10 +683,23 @@
"""
- bandwidth = self.bts1.bandwidth
- rb_ratio = float(
- self.bts1.nrb_ul) / self.total_rbs_dictionary[bandwidth]
- mcs = self.bts1.lte_mcs_ul
+ return self.bts_maximum_uplink_throughtput(self.bts1)
+
+ def bts_maximum_uplink_throughtput(self, bts):
+ """ Calculates maximum achievable uplink throughput for the selected
+ basestation.
+
+ Args:
+ bts: basestation handle
+
+ Returns:
+ Maximum throughput in mbps.
+
+ """
+
+ bandwidth = bts.bandwidth
+ rb_ratio = float(bts.nrb_ul) / self.total_rbs_dictionary[bandwidth]
+ mcs = bts.lte_mcs_ul
max_rate_per_stream = None
if mcs == "23" and not self.ul_64_qam:
diff --git a/acts/framework/acts/test_utils/power/tel_simulations/UmtsSimulation.py b/acts/framework/acts/test_utils/power/tel_simulations/UmtsSimulation.py
index a2cb7ac..aa89d01 100644
--- a/acts/framework/acts/test_utils/power/tel_simulations/UmtsSimulation.py
+++ b/acts/framework/acts/test_utils/power/tel_simulations/UmtsSimulation.py
@@ -107,22 +107,18 @@
Args:
parameters: list of parameters
- Returns:
- False if there was an error while parsing the config
"""
- if not super().parse_parameters(parameters):
- return False
+ super().parse_parameters(parameters)
# Setup band
values = self.consume_parameter(parameters, self.PARAM_BAND, 1)
if not values:
- self.log.error(
+ raise ValueError(
"The test name needs to include parameter '{}' followed by "
"the required band number.".format(self.PARAM_BAND))
- return False
self.set_band(self.bts1, values[1])
@@ -135,10 +131,9 @@
self.PARAM_RELEASE_VERSION_7, self.PARAM_RELEASE_VERSION_8,
self.PARAM_RELEASE_VERSION_99
]:
- self.log.error(
+ raise ValueError(
"The test name needs to include the parameter {} followed by a "
"valid release version.".format(self.PARAM_RELEASE_VERSION))
- return False
self.set_release_version(self.bts1, values[1])
@@ -146,13 +141,12 @@
values = self.consume_parameter(parameters, self.PARAM_UL_PW, 1)
if not values or values[1] not in self.uplink_signal_level_dictionary:
- self.log.error(
+ raise ValueError(
"The test name needs to include parameter {} followed by "
"one the following values: {}.".format(self.PARAM_UL_PW, [
"\n" + val
for val in self.uplink_signal_level_dictionary.keys()
]))
- return False
# Power is not set on the callbox until after the simulation is
# started. Will save this value in a variable and use it later
@@ -163,22 +157,16 @@
values = self.consume_parameter(parameters, self.PARAM_DL_PW, 1)
if not values or values[1] not in self.downlink_rscp_dictionary:
- self.log.error(
+ raise ValueError(
"The test name needs to include parameter {} followed by "
"one of the following values: {}.".format(
- self.PARAM_DL_PW, [
- "\n" + val
- for val in self.downlink_rscp_dictionary.keys()
- ]))
- return False
+ self.PARAM_DL_PW,
+ [val for val in self.downlink_rscp_dictionary.keys()]))
# Power is not set on the callbox until after the simulation is
# started. Will save this value in a variable and use it later
self.sim_dl_power = self.downlink_rscp_dictionary[values[1]]
- # No errors were found
- return True
-
def set_release_version(self, bts, release_version):
""" Sets the release version.
diff --git a/acts/framework/acts/test_utils/tel/TelephonyBaseTest.py b/acts/framework/acts/test_utils/tel/TelephonyBaseTest.py
index d158e25..05ec9e2 100644
--- a/acts/framework/acts/test_utils/tel/TelephonyBaseTest.py
+++ b/acts/framework/acts/test_utils/tel/TelephonyBaseTest.py
@@ -451,8 +451,8 @@
def _take_bug_report(self, test_name, begin_time):
test_log_path = os.path.join(self.log_path, test_name)
utils.create_dir(test_log_path)
- # Extract test_run_info.txt, test_run_detail.txt
- for file_name in ("test_run_info.txt", "test_run_details.txt"):
+ # Extract test_run_info.txt, test_run_debug.txt
+ for file_name in ("test_run_info.txt", "test_run_debug.txt"):
extract_test_log(self.log, os.path.join(self.log_path, file_name),
os.path.join(test_log_path,
"%s_%s" % (test_name, file_name)),
diff --git a/acts/framework/acts/test_utils/tel/tel_data_utils.py b/acts/framework/acts/test_utils/tel/tel_data_utils.py
index f7d397f..1c384eb 100644
--- a/acts/framework/acts/test_utils/tel/tel_data_utils.py
+++ b/acts/framework/acts/test_utils/tel/tel_data_utils.py
@@ -381,8 +381,7 @@
return False
if not ad.droid.connectivityNetworkIsConnected():
- ad.log.error("Network is NOT connected!")
- return False
+ ad.log.warning("Network is NOT connected!")
if not wait_for_cell_data_connection(log, ad, True):
ad.log.error("Failed to enable cell data connection")
diff --git a/acts/framework/acts/test_utils/tel/tel_test_utils.py b/acts/framework/acts/test_utils/tel/tel_test_utils.py
index 07df355..37e9ddb 100644
--- a/acts/framework/acts/test_utils/tel/tel_test_utils.py
+++ b/acts/framework/acts/test_utils/tel/tel_test_utils.py
@@ -4404,7 +4404,8 @@
ad_tx.log.warning("No %s or %s event.", EventMmsSentSuccess,
EventMmsSentFailure)
- if not wait_for_matching_mms(log, ad_rx, phonenumber_tx, message):
+ if not wait_for_matching_mms(log, ad_rx, phonenumber_tx,
+ message, max_wait_time):
return False
except Exception as e:
log.error("Exception error %s", e)
diff --git a/acts/framework/acts/test_utils/wifi/wifi_test_utils.py b/acts/framework/acts/test_utils/wifi/wifi_test_utils.py
index 67bac00..6d70aca 100755
--- a/acts/framework/acts/test_utils/wifi/wifi_test_utils.py
+++ b/acts/framework/acts/test_utils/wifi/wifi_test_utils.py
@@ -16,7 +16,7 @@
import logging
import os
-import pprint
+import shutil
import time
from enum import IntEnum
@@ -49,12 +49,12 @@
"AP1_on_AP2_off": [
0,
0,
- 95,
- 95
+ 60,
+ 60
],
"AP1_off_AP2_on": [
- 95,
- 95,
+ 60,
+ 60,
0,
0
],
@@ -1664,6 +1664,36 @@
attn_val_name)
raise
+def set_attns_steps(attenuator, attn_val_name, steps=10, wait_time=12):
+ """Sets attenuation values on attenuators used in this test.
+
+ Args:
+ attenuator: The attenuator object.
+ attn_val_name: Name of the attenuation value pair to use.
+ steps: Number of attenuator changes to reach the target value.
+ wait_time: Sleep time for each change of attenuator.
+ """
+ logging.info("Set attenuation values to %s in %d step(s)", roaming_attn[attn_val_name], steps)
+ current_atten = [
+ attenuator[0].get_atten(), attenuator[1].get_atten(),
+ attenuator[2].get_atten(), attenuator[3].get_atten()]
+ target_atten = [
+ roaming_attn[attn_val_name][0], roaming_attn[attn_val_name][1],
+ roaming_attn[attn_val_name][2], roaming_attn[attn_val_name][3]]
+ while steps > 0:
+ next_atten = list(map(
+ lambda x, y: round((y + (steps - 1) * x) / steps) , current_atten, target_atten))
+ try:
+ attenuator[0].set_atten(next_atten[0])
+ attenuator[1].set_atten(next_atten[1])
+ attenuator[2].set_atten(next_atten[2])
+ attenuator[3].set_atten(next_atten[3])
+ time.sleep(wait_time)
+ except:
+ logging.exception("Failed to set attenuation values %s.", attn_val_name)
+ raise
+ current_atten = next_atten
+ steps = steps - 1
def trigger_roaming_and_validate(dut, attenuator, attn_val_name, expected_con):
"""Sets attenuators to trigger roaming and validate the DUT connected
@@ -1678,9 +1708,7 @@
WifiEnums.SSID_KEY: expected_con[WifiEnums.SSID_KEY],
WifiEnums.BSSID_KEY: expected_con["bssid"],
}
- set_attns(attenuator, attn_val_name)
- logging.info("Wait %ss for roaming to finish.", ROAMING_TIMEOUT)
- time.sleep(ROAMING_TIMEOUT)
+ set_attns_steps(attenuator, attn_val_name)
verify_wifi_connection_info(dut, expected_con)
expected_bssid = expected_con[WifiEnums.BSSID_KEY]
@@ -1710,8 +1738,8 @@
test_name: test name to be used for pcap file name
Returns:
- Dictionary with pid of the tcpdump process as key and log path
- of the file name as the value
+ Dictionary with wifi band as key and the tuple
+ (pcap Process object, log directory) as the value
"""
log_dir = os.path.join(log_path, test_name)
utils.create_dir(log_dir)
@@ -1719,13 +1747,13 @@
bands = [BAND_2G, BAND_5G]
else:
bands = [wifi_band]
- pids = {}
+ procs = {}
for band in bands:
- pid = pcap.start_packet_capture(band, log_dir, test_name)
- pids[pid] = os.path.join(log_dir, test_name)
- return pids
+ proc = pcap.start_packet_capture(band, log_dir, test_name)
+ procs[band] = (proc, os.path.join(log_dir, test_name))
+ return procs
-def stop_pcap(pcap, pids, test_status=None):
+def stop_pcap(pcap, procs, test_status=None):
"""Stop packet capture in monitor mode.
Since, the pcap logs in monitor mode can be very large, we will
@@ -1734,14 +1762,14 @@
Args:
pcap: packet capture object
- pids: dictionary returned by start_pcap
+ procs: dictionary returned by start_pcap
test_status: status of the test case
"""
- for pid, fname in pids.items():
- pcap.stop_packet_capture(pid)
+ for proc, fname in procs.values():
+ pcap.stop_packet_capture(proc)
if test_status:
- os.system('rm -rf %s' % os.path.dirname(fname))
+ shutil.rmtree(os.path.dirname(fname))
def start_cnss_diags(ads):
for ad in ads:
diff --git a/acts/framework/tests/acts_import_test_utils_test.py b/acts/framework/tests/acts_import_test_utils_test.py
index a0a66fd..c44522c 100755
--- a/acts/framework/tests/acts_import_test_utils_test.py
+++ b/acts/framework/tests/acts_import_test_utils_test.py
@@ -16,39 +16,6 @@
import unittest
-from acts import utils
-from acts.test_utils.bt import BleEnum
-from acts.test_utils.bt import BluetoothBaseTest
-from acts.test_utils.bt import BluetoothCarHfpBaseTest
-from acts.test_utils.bt import BtEnum
-from acts.test_utils.bt import GattConnectedBaseTest
-from acts.test_utils.bt import GattEnum
-from acts.test_utils.bt import bt_contacts_utils
-from acts.test_utils.bt import bt_gatt_utils
-from acts.test_utils.bt import bt_test_utils
-from acts.test_utils.bt import native_bt_test_utils
-
-from acts.test_utils.car import car_bt_utils
-from acts.test_utils.car import car_media_utils
-from acts.test_utils.car import car_telecom_utils
-from acts.test_utils.car import tel_telecom_utils
-
-from acts.test_utils.net import connectivity_const
-from acts.test_utils.net import connectivity_const
-
-from acts.test_utils.tel import TelephonyBaseTest
-from acts.test_utils.tel import tel_atten_utils
-from acts.test_utils.tel import tel_data_utils
-from acts.test_utils.tel import tel_defines
-from acts.test_utils.tel import tel_lookup_tables
-from acts.test_utils.tel import tel_subscription_utils
-from acts.test_utils.tel import tel_test_utils
-from acts.test_utils.tel import tel_video_utils
-from acts.test_utils.tel import tel_voice_utils
-
-from acts.test_utils.wifi import wifi_constants
-from acts.test_utils.wifi import wifi_test_utils
-
class ActsImportTestUtilsTest(unittest.TestCase):
"""This test class has unit tests for the implementation of everything
@@ -60,8 +27,44 @@
This test will fail if any import was unsuccessful.
"""
- self.assertTrue(True)
+ try:
+ from acts import utils
+
+ from acts.test_utils.bt import BleEnum
+ from acts.test_utils.bt import BluetoothBaseTest
+ from acts.test_utils.bt import BluetoothCarHfpBaseTest
+ from acts.test_utils.bt import BtEnum
+ from acts.test_utils.bt import GattConnectedBaseTest
+ from acts.test_utils.bt import GattEnum
+ from acts.test_utils.bt import bt_contacts_utils
+ from acts.test_utils.bt import bt_gatt_utils
+ from acts.test_utils.bt import bt_test_utils
+ from acts.test_utils.bt import native_bt_test_utils
+
+ from acts.test_utils.car import car_bt_utils
+ from acts.test_utils.car import car_media_utils
+ from acts.test_utils.car import car_telecom_utils
+ from acts.test_utils.car import tel_telecom_utils
+
+ from acts.test_utils.net import connectivity_const
+ from acts.test_utils.net import connectivity_const
+
+ from acts.test_utils.tel import TelephonyBaseTest
+ from acts.test_utils.tel import tel_atten_utils
+ from acts.test_utils.tel import tel_data_utils
+ from acts.test_utils.tel import tel_defines
+ from acts.test_utils.tel import tel_lookup_tables
+ from acts.test_utils.tel import tel_subscription_utils
+ from acts.test_utils.tel import tel_test_utils
+ from acts.test_utils.tel import tel_video_utils
+ from acts.test_utils.tel import tel_voice_utils
+
+ from acts.test_utils.wifi import wifi_constants
+ from acts.test_utils.wifi import wifi_test_utils
+
+ except Exception:
+ self.fail('Unable to import all supported test_utils')
-if __name__ == "__main__":
+if __name__ == '__main__':
unittest.main()
diff --git a/acts/framework/tests/libs/logging/log_stream_test.py b/acts/framework/tests/libs/logging/log_stream_test.py
index 6c9b264..37fc803 100755
--- a/acts/framework/tests/libs/logging/log_stream_test.py
+++ b/acts/framework/tests/libs/logging/log_stream_test.py
@@ -89,10 +89,10 @@
msg='__validate_styles did not raise the expected error message')
@mock.patch('os.makedirs')
- def test_validate_styles_raises_when_both_testclass_and_testcase_set(
+ def test_validate_styles_raises_when_multiple_file_outputs_set(
self, *_):
- """Tests that a style is invalid if both TESTCLASS_LOG and TESTCASE_LOG
- locations are set for the same log level.
+ """Tests that a style is invalid if more than one of MONOLITH_LOG,
+ TESTCLASS_LOG, and TESTCASE_LOG is set for the same log level.
If the error is NOT raised, then a LogStream can create a Logger that
has multiple LogHandlers trying to write to the same file.
@@ -103,7 +103,26 @@
log_styles=[LogStyles.LOG_DEBUG | LogStyles.TESTCASE_LOG,
LogStyles.LOG_DEBUG | LogStyles.TESTCLASS_LOG])
self.assertTrue(
- 'Both TESTCLASS_LOG' in catch.exception.args[0],
+ 'More than one of' in catch.exception.args[0],
+ msg='__validate_styles did not raise the expected error message')
+
+ with self.assertRaises(InvalidStyleSetError) as catch:
+ log_stream.create_logger(
+ self._testMethodName,
+ log_styles=[LogStyles.LOG_DEBUG | LogStyles.TESTCASE_LOG,
+ LogStyles.LOG_DEBUG | LogStyles.MONOLITH_LOG])
+ self.assertTrue(
+ 'More than one of' in catch.exception.args[0],
+ msg='__validate_styles did not raise the expected error message')
+
+ with self.assertRaises(InvalidStyleSetError) as catch:
+ log_stream.create_logger(
+ self._testMethodName,
+ log_styles=[LogStyles.LOG_DEBUG | LogStyles.TESTCASE_LOG,
+ LogStyles.LOG_DEBUG | LogStyles.TESTCLASS_LOG,
+ LogStyles.LOG_DEBUG | LogStyles.MONOLITH_LOG])
+ self.assertTrue(
+ 'More than one of' in catch.exception.args[0],
msg='__validate_styles did not raise the expected error message')
@mock.patch('os.makedirs')
@@ -189,8 +208,7 @@
"""Tests that handle_style does not create test case and test class
only descriptors without LogStyle.TESTCASE_LOG.
"""
- info_monolith_log = (LogStyles.LOG_INFO + LogStyles.MONOLITH_LOG +
- LogStyles.TESTCLASS_LOG)
+ info_monolith_log = (LogStyles.LOG_INFO + LogStyles.MONOLITH_LOG)
with self.patch('FileHandler'):
log_stream.create_logger(self._testMethodName,
@@ -232,8 +250,7 @@
"""Tests that handle_style does not create test class descriptors
without LogStyle.TESTCLASS_LOG.
"""
- info_monolith_log = (LogStyles.LOG_INFO + LogStyles.MONOLITH_LOG +
- LogStyles.TESTCASE_LOG)
+ info_monolith_log = (LogStyles.LOG_INFO + LogStyles.MONOLITH_LOG)
with self.patch('FileHandler'):
log_stream.create_logger(self._testMethodName,
@@ -379,7 +396,9 @@
"""Tests that the handlers generated from the descriptors are added
to the associated logger and the given handlers list."""
info_testcase_log = LogStyles.LOG_INFO + LogStyles.TESTCASE_LOG
- with self.patch('FileHandler'):
+ with self.patch('FileHandler',
+ side_effect=[mock.MagicMock(name='handler1'),
+ mock.MagicMock(name='handler2')]):
log_stream.create_logger(self._testMethodName,
log_styles=info_testcase_log)
@@ -416,16 +435,16 @@
def test_on_test_case_end_enables_class_level_handlers(self, *_):
info_testcase_log = LogStyles.LOG_INFO + LogStyles.TESTCASE_LOG
with self.patch('FileHandler',
- side_effect=[mock.MagicMock(name='class_handler'),
+ side_effect=[mock.MagicMock(name='run_handler'),
+ mock.MagicMock(name='class_handler'),
mock.MagicMock(name='case_handler')]):
log_stream.create_logger(self._testMethodName,
log_styles=info_testcase_log)
created_log_stream = log_stream._log_streams[self._testMethodName]
created_log_stream.on_test_class_begin(TestClassBeginEvent(TestClass()))
- for handler in created_log_stream.logger.handlers:
- if not isinstance(handler, logging.NullHandler):
- created_log_stream.logger.removeHandler(handler)
+ created_log_stream.on_test_case_begin(
+ TestCaseBeginEvent(TestClass(), TestClass.test_case))
created_log_stream.on_test_case_end('')
self.assertGreater(
@@ -455,15 +474,15 @@
def test_on_test_case_begin_disables_class_level_handlers(self, *_):
info_testcase_log = LogStyles.LOG_INFO + LogStyles.TESTCASE_LOG
with self.patch('FileHandler',
- side_effect=[mock.MagicMock(name='class_handler'),
+ side_effect=[mock.MagicMock(name='run_handler'),
+ mock.MagicMock(name='class_handler'),
mock.MagicMock(name='case_handler')]):
log_stream.create_logger(self._testMethodName,
log_styles=info_testcase_log)
created_log_stream = log_stream._log_streams[self._testMethodName]
- created_log_stream.on_test_class_begin(
- TestClassBeginEvent(TestClass()))
+ created_log_stream.on_test_class_begin(TestClassBeginEvent(TestClass()))
created_log_stream.on_test_case_begin(
TestCaseBeginEvent(TestClass(), TestClass.test_case))
@@ -495,6 +514,27 @@
0, 'The test class only log handlers were not '
'cleared.')
+ @mock.patch('os.makedirs')
+ def test_on_test_class_end_enables_run_level_handlers(self, *_):
+ info_testclass_log = LogStyles.LOG_INFO + LogStyles.TESTCLASS_LOG
+ with self.patch('FileHandler',
+ side_effect=[mock.MagicMock(name='run_handler'),
+ mock.MagicMock(name='class_handler')]):
+ log_stream.create_logger(self._testMethodName,
+ log_styles=info_testclass_log)
+
+ created_log_stream = log_stream._log_streams[self._testMethodName]
+ created_log_stream.on_test_class_begin(TestClassBeginEvent(TestClass()))
+ created_log_stream.on_test_class_end('')
+
+ self.assertGreater(
+ len(created_log_stream._test_run_only_log_handlers), 0,
+ 'The test run only log handlers list is empty.')
+ for handler in created_log_stream._test_run_only_log_handlers:
+ self.assertIn(handler, created_log_stream.logger.handlers,
+ 'A run level handler is not enabled on test class '
+ 'end.')
+
# on_test_class_begin
@mock.patch('os.makedirs')
@@ -514,6 +554,27 @@
self.assertEqual(len(created_log_stream._test_class_only_log_handlers),
1)
+ @mock.patch('os.makedirs')
+ def test_on_test_class_begin_disables_run_level_handlers(self, *_):
+ info_testclass_log = LogStyles.LOG_INFO + LogStyles.TESTCLASS_LOG
+ with self.patch('FileHandler',
+ side_effect=[mock.MagicMock(name='run_handler'),
+ mock.MagicMock(name='class_handler')]):
+ log_stream.create_logger(self._testMethodName,
+ log_styles=info_testclass_log)
+
+ created_log_stream = log_stream._log_streams[self._testMethodName]
+
+ created_log_stream.on_test_class_begin(TestClassBeginEvent(TestClass()))
+
+ self.assertGreater(
+ len(created_log_stream._test_run_only_log_handlers), 0,
+ 'The test run only log handlers list is empty.')
+ for handler in created_log_stream._test_run_only_log_handlers:
+ self.assertNotIn(handler, created_log_stream.logger.handlers,
+ 'A run level handler is not disabled on test '
+ 'class begin.')
+
# cleanup
@mock.patch('os.makedirs')
diff --git a/acts/framework/tests/libs/proc/process_test.py b/acts/framework/tests/libs/proc/process_test.py
index 5ed2dc9..b327c0e 100644
--- a/acts/framework/tests/libs/proc/process_test.py
+++ b/acts/framework/tests/libs/proc/process_test.py
@@ -18,7 +18,7 @@
import mock
import subprocess
from acts.libs.proc.process import Process
-
+from acts.libs.proc.process import ProcessError
class FakeThread(object):
def __init__(self, target=None):
@@ -78,6 +78,25 @@
# start
+ def test_start_raises_if_called_back_to_back(self):
+ """Tests that start raises an exception if it has already been called
+ prior.
+
+ This is required to prevent references to processes and threads from
+ being overwritten, potentially causing ACTS to hang."""
+ process = Process('cmd')
+
+ # Here we need the thread to start the process object.
+ class FakeThreadImpl(FakeThread):
+ def _on_start(self):
+ process._process = mock.Mock()
+
+ with self.patch('Thread', FakeThreadImpl):
+ process.start()
+ expected_msg = 'Process has already started.'
+ with self.assertRaisesRegex(ProcessError, expected_msg):
+ process.start()
+
def test_start_starts_listening_thread(self):
"""Tests that start starts the _exec_popen_loop function."""
process = Process('cmd')
@@ -95,6 +114,17 @@
# wait
+ def test_wait_raises_if_called_back_to_back(self):
+ """Tests that wait raises an exception if it has already been called
+ prior."""
+ process = Process('cmd')
+ process._process = mock.Mock()
+
+ process.wait(0)
+ expected_msg = 'Process is already being stopped.'
+ with self.assertRaisesRegex(ProcessError, expected_msg):
+ process.wait(0)
+
def test_wait_kills_after_timeout(self):
"""Tests that if a TimeoutExpired error is thrown during wait, the
process is killed."""
@@ -207,6 +237,7 @@
process._process = mock.Mock()
process._process.poll.return_value = None
process._process.kill = test_call_order
+ process._process.wait.side_effect = subprocess.TimeoutExpired('', '')
process.stop()
diff --git a/acts/tests/google/ble/gatt/GattConnectTest.py b/acts/tests/google/ble/gatt/GattConnectTest.py
index 329405d..c276c0e 100644
--- a/acts/tests/google/ble/gatt/GattConnectTest.py
+++ b/acts/tests/google/ble/gatt/GattConnectTest.py
@@ -279,6 +279,7 @@
autoconnect = False
mac_address, adv_callback, scan_callback = (
get_mac_address_of_generic_advertisement(self.cen_ad, self.per_ad))
+ self.adv_instances.append(adv_callback)
try:
bluetooth_gatt, gatt_callback = setup_gatt_connection(
self.cen_ad, mac_address, autoconnect)
@@ -357,6 +358,7 @@
transport=gatt_transport['auto'],
opportunistic=False)
self.cen_ad.droid.bleStopBleScan(scan_callback)
+ self.adv_instances.append(adv_callback)
self.bluetooth_gatt_list.append(bluetooth_gatt_1)
except GattTestUtilsError as err:
self.log.error(err)
@@ -931,11 +933,22 @@
and device['name'] == target_name):
bonded = True
break
+
+ # Dual mode devices will establish connection over the classic transport,
+ # in order to establish bond over both transports, and do SDP. Starting
+ # disconnection before all this is finished is not safe, might lead to
+ # race conditions, i.e. bond over classic tranport shows up after LE
+ # bond is already removed.
+ time.sleep(4)
+
for ad in [self.cen_ad, self.per_ad]:
if not clear_bonded_devices(ad):
return False
- # Necessary sleep time for entries to update unbonded state
- time.sleep(2)
+
+ # Necessary sleep time for entries to update unbonded state
+ time.sleep(2)
+
+ for ad in [self.cen_ad, self.per_ad]:
bonded_devices = ad.droid.bluetoothGetBondedDevices()
if len(bonded_devices) > 0:
self.log.error(
@@ -1096,16 +1109,24 @@
self.per_ad.droid.bleStartBleAdvertising(
advertise_callback, advertise_data, advertise_settings)
- try:
- mac_address_post_restart = self.cen_ad.ed.pop_event(
- expected_event_name, self.default_timeout)['data']['Result'][
- 'deviceInfo']['address']
- self.log.info(
- "Peripheral advertisement found with mac address: {}".format(
- mac_address_post_restart))
- except Empty:
- self.log.info("Peripheral advertisement not found")
- test_result = False
+ mac_address_post_restart = mac_address_pre_restart
+
+ while True:
+ try:
+ mac_address_post_restart = self.cen_ad.ed.pop_event(
+ expected_event_name, self.default_timeout)['data']['Result'][
+ 'deviceInfo']['address']
+ self.log.info(
+ "Peripheral advertisement found with mac address: {}".format(
+ mac_address_post_restart))
+ except Empty:
+ self.log.info("Peripheral advertisement not found")
+ test_result = False
+
+ if mac_address_pre_restart != mac_address_post_restart:
+ break
+
+ self.cen_ad.droid.bleStopBleScan(scan_callback)
# Steps 4: Try to connect to the first mac address
gatt_callback = self.cen_ad.droid.gattCreateGattCallback()
@@ -1128,8 +1149,12 @@
# Step 5: Cancel connection request.
self.cen_ad.droid.gattClientDisconnect(bluetooth_gatt)
+ close_gatt_client(self.cen_ad, bluetooth_gatt)
+ if bluetooth_gatt in self.bluetooth_gatt_list:
+ self.bluetooth_gatt_list.remove(bluetooth_gatt)
# Step 6: Connect to second mac address.
+ gatt_callback = self.cen_ad.droid.gattCreateGattCallback()
self.log.info(
"Gatt Connect to mac address {}.".format(mac_address_post_restart))
bluetooth_gatt = self.cen_ad.droid.gattClientConnectGatt(
@@ -1152,4 +1177,8 @@
except Empty:
self.log.error("No connection update was found.")
return False
- return self.cen_ad.droid.gattClientDisconnect(bluetooth_gatt)
+
+ self.per_ad.droid.bleStopBleAdvertising(advertise_callback)
+
+ return self._orchestrate_gatt_disconnection(bluetooth_gatt,
+ gatt_callback)
diff --git a/acts/tests/google/bt/headphone_automation/HeadphoneTest.py b/acts/tests/google/bt/headphone_automation/HeadphoneTest.py
index 943f548..74eda7a 100644
--- a/acts/tests/google/bt/headphone_automation/HeadphoneTest.py
+++ b/acts/tests/google/bt/headphone_automation/HeadphoneTest.py
@@ -99,6 +99,9 @@
headphone.power_off()
headphone.clean_up()
+ power_supply = self.relay_devices[-1]
+ power_supply.power_off()
+
return clear_bonded_devices(self.ad)
@property
@@ -107,7 +110,7 @@
@property
def headphone_list(self):
- return self.relay_devices
+ return self.relay_devices[:-1]
@BluetoothBaseTest.bt_test_wrap
@test_tracker_info(uuid='157c1fa1-3d6f-4cfc-8f86-ad267746af71')
diff --git a/acts/tests/google/bt/performance/BtRangeCodecTest.py b/acts/tests/google/bt/performance/BtRangeCodecTest.py
new file mode 100755
index 0000000..252c587
--- /dev/null
+++ b/acts/tests/google/bt/performance/BtRangeCodecTest.py
@@ -0,0 +1,38 @@
+from acts.test_utils.bt.A2dpCodecBaseTest import A2dpCodecBaseTest
+
+
+# For more intuitive parameter parsing.
+# If we are able to 'step' to end value, include it in the range.
+def inclusive_range(start, stop, step):
+ for i in range(start, stop, step):
+ yield i
+ if stop % step == 0:
+ yield stop
+
+
+class BtRangeCodecTest(A2dpCodecBaseTest):
+
+ def __init__(self, configs):
+ super().__init__(configs)
+ self.attenuator = self.attenuators[0]
+ req_params = ["bt_atten_start", "bt_atten_stop", "bt_atten_step",
+ "codecs"]
+ opt_params = ["RelayDevice", "required_devices", "audio_params"]
+ self.unpack_userparams(req_params, opt_params)
+ attenuation_range = inclusive_range(self.bt_atten_start,
+ self.bt_atten_stop,
+ self.bt_atten_step)
+ for attenuation in attenuation_range:
+ for codec_config in self.codecs:
+ self.generate_test_case(codec_config, attenuation)
+
+ def generate_test_case(self, codec_config, attenuation):
+ def test_case_fn():
+ self.attenuator.set_atten(attenuation)
+ self.log.info("Setting bt attenuation to %s" % attenuation)
+ self.stream_music_on_codec(**codec_config)
+ test_case_name = "test_streaming_{}".format(
+ "_".join([str(codec_config[key]) for key in sorted(
+ codec_config.keys(), reverse=True)] + [str(attenuation)])
+ )
+ setattr(self, test_case_name, test_case_fn)
diff --git a/acts/tests/google/power/tel/lab/PowerTelTestplanDataTest.py b/acts/tests/google/power/tel/lab/PowerTelTestplanDataTest.py
new file mode 100644
index 0000000..43888c5
--- /dev/null
+++ b/acts/tests/google/power/tel/lab/PowerTelTestplanDataTest.py
@@ -0,0 +1,222 @@
+#!/usr/bin/env python3.4
+#
+# Copyright 2018 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from PowerTelTrafficTest import PowerTelTrafficTest
+
+class PowerTelTraffic_LTE_Test(PowerTelTrafficTest):
+ def test_lte_traffic_band_2_pdl_excellent_pul_low_bw_14_tm_1_mimo_1x1_scheduling_static_direction_ul_pattern_0_100_1(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_2_pdl_excellent_pul_low_bw_3_tm_1_mimo_1x1_scheduling_static_direction_ul_pattern_0_100_2(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_2_pdl_excellent_pul_low_bw_5_tm_1_mimo_1x1_scheduling_static_direction_ul_pattern_0_100_3(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_2_pdl_excellent_pul_low_bw_10_tm_1_mimo_1x1_scheduling_static_direction_ul_pattern_0_100_4(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_2_pdl_excellent_pul_low_bw_15_tm_1_mimo_1x1_scheduling_static_direction_ul_pattern_0_100_5(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_2_pdl_excellent_pul_low_bw_20_tm_1_mimo_1x1_scheduling_static_direction_ul_pattern_0_100_6(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_13_pdl_excellent_pul_max_bw_5_tm_1_mimo_1x1_scheduling_static_direction_ul_pattern_0_100_7(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_13_pdl_excellent_pul_high_bw_5_tm_1_mimo_1x1_scheduling_static_direction_ul_pattern_0_100_8(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_13_pdl_excellent_pul_medium_bw_5_tm_1_mimo_1x1_scheduling_static_direction_ul_pattern_0_100_9(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_13_pdl_excellent_pul_low_bw_5_tm_1_mimo_1x1_scheduling_static_direction_ul_pattern_0_100_10(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_13_pdl_excellent_pul_low_bw_5_tm_1_mimo_1x1_scheduling_static_direction_dl_pattern_100_0_11(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_13_pdl_excellent_pul_low_bw_5_tm_1_mimo_1x1_scheduling_static_direction_dlul_pattern_50_50_12(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_13_pdl_excellent_pul_low_bw_5_tm_1_mimo_1x1_scheduling_static_direction_dlul_pattern_75_25_13(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_13_pdl_excellent_pul_low_bw_5_tm_1_mimo_1x1_scheduling_static_direction_dlul_pattern_90_10_14(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_4_pdl_excellent_pul_low_bw_5_tm_1_mimo_1x1_scheduling_static_direction_dl_pattern_100_0_15(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_4_pdl_excellent_pul_low_bw_5_tm_4_mimo_2x2_scheduling_static_direction_dl_pattern_100_0_16(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_4_pdl_excellent_pul_max_bw_5_tm_3_mimo_4x4_scheduling_static_direction_dl_pattern_100_0_17(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_4_pdl_excellent_pul_low_bw_5_tm_3_mimo_4x4_scheduling_static_direction_dl_pattern_100_0_18(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_7_pdl_excellent_pul_max_bw_20_tm_1_mimo_1x1_scheduling_static_direction_ul_pattern_0_100_19(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_7_pdl_excellent_pul_high_bw_20_tm_1_mimo_1x1_scheduling_static_direction_ul_pattern_0_100_20(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_7_pdl_excellent_pul_medium_bw_20_tm_1_mimo_1x1_scheduling_static_direction_ul_pattern_0_100_21(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_7_pdl_excellent_pul_low_bw_20_tm_1_mimo_1x1_scheduling_static_direction_ul_pattern_0_100_22(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_2_pdl_excellent_pul_max_bw_5_tm_1_mimo_1x1_scheduling_static_direction_ul_pattern_0_100_29(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_4_pdl_excellent_pul_max_bw_5_tm_1_mimo_1x1_scheduling_static_direction_ul_pattern_0_100_30(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_5_pdl_excellent_pul_max_bw_5_tm_1_mimo_1x1_scheduling_static_direction_ul_pattern_0_100_31(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_7_pdl_excellent_pul_max_bw_5_tm_1_mimo_1x1_scheduling_static_direction_ul_pattern_0_100_32(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_12_pdl_excellent_pul_max_bw_5_tm_1_mimo_1x1_scheduling_static_direction_ul_pattern_0_100_33(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_13_pdl_excellent_pul_max_bw_10_tm_1_mimo_1x1_scheduling_static_direction_dl_pattern_100_0_34(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_4_pdl_excellent_pul_max_bw_10_tm_1_mimo_1x1_scheduling_static_direction_dl_pattern_100_0_35(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_7_pdl_excellent_pul_max_bw_10_tm_1_mimo_1x1_scheduling_static_direction_dl_pattern_100_0_36(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_3_pdl_excellent_pul_max_bw_10_tm_1_mimo_1x1_scheduling_static_direction_dl_pattern_100_0_37(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_1_pdl_excellent_pul_medium_bw_20_tm_3_mimo_4x4_scheduling_static_direction_dl_pattern_100_0_38(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_2_pdl_excellent_pul_medium_bw_20_tm_3_mimo_4x4_scheduling_static_direction_dl_pattern_100_0_39(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_3_pdl_excellent_pul_medium_bw_20_tm_3_mimo_4x4_scheduling_static_direction_dl_pattern_100_0_40(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_4_pdl_excellent_pul_medium_bw_20_tm_3_mimo_4x4_scheduling_static_direction_dl_pattern_100_0_41(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_7_pdl_excellent_pul_medium_bw_20_tm_3_mimo_4x4_scheduling_static_direction_dl_pattern_100_0_42(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_1_pdl_excellent_pul_low_bw_10_tm_4_mimo_2x2_scheduling_static_direction_dlul_pattern_75_25_43(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_2_pdl_excellent_pul_low_bw_10_tm_4_mimo_2x2_scheduling_static_direction_dlul_pattern_75_25_44(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_3_pdl_excellent_pul_low_bw_10_tm_4_mimo_2x2_scheduling_static_direction_dlul_pattern_75_25_45(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_4_pdl_excellent_pul_low_bw_10_tm_4_mimo_2x2_scheduling_static_direction_dlul_pattern_75_25_46(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_5_pdl_excellent_pul_low_bw_10_tm_4_mimo_2x2_scheduling_static_direction_dlul_pattern_75_25_47(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_7_pdl_excellent_pul_low_bw_10_tm_4_mimo_2x2_scheduling_static_direction_dlul_pattern_75_25_48(self):
+ self.power_tel_traffic_test()
+
+ def test_lte_traffic_band_12_pdl_excellent_pul_low_bw_10_tm_4_mimo_2x2_scheduling_static_direction_dlul_pattern_75_25_49(self):
+ self.power_tel_traffic_test()
+
+class PowerTelTraffic_UMTS_Test(PowerTelTrafficTest):
+ def test_umts_traffic_r_8_band_1_pul_edge_direction_ul_pattern_0_100_1(self):
+ self.power_tel_traffic_test()
+
+ def test_umts_traffic_r_8_band_1_pul_weak_direction_ul_pattern_0_100_2(self):
+ self.power_tel_traffic_test()
+
+ def test_umts_traffic_r_8_band_1_pul_medium_direction_ul_pattern_0_100_3(self):
+ self.power_tel_traffic_test()
+
+ def test_umts_traffic_r_8_band_1_pul_excellent_direction_ul_pattern_0_100_4(self):
+ self.power_tel_traffic_test()
+
+ def test_umts_traffic_r_7_band_1_pul_excellent_direction_ul_pattern_0_100_5(self):
+ self.power_tel_traffic_test()
+
+ def test_umts_traffic_r_99_band_1_pul_excellent_direction_ul_pattern_0_100_6(self):
+ self.power_tel_traffic_test()
+
+ def test_umts_traffic_r_8_band_4_pul_excellent_direction_ul_pattern_0_100_7(self):
+ self.power_tel_traffic_test()
+
+ def test_umts_traffic_r_8_band_5_pul_excellent_direction_ul_pattern_0_100_8(self):
+ self.power_tel_traffic_test()
+
+ def test_umts_traffic_r_8_band_5_pul_excellent_direction_dl_pattern_100_0_9(self):
+ self.power_tel_traffic_test()
+
+ def test_umts_traffic_r_8_band_5_pul_excellent_direction_dlul_pattern_90_10_10(self):
+ self.power_tel_traffic_test()
+
+ def test_umts_traffic_r_8_band_5_pul_excellent_direction_dlul_pattern_75_25_11(self):
+ self.power_tel_traffic_test()
+
+ def test_umts_traffic_r_8_band_5_pul_excellent_direction_dlul_pattern_50_50_12(self):
+ self.power_tel_traffic_test()
+
+ def test_umts_traffic_r_7_band_4_pul_edge_direction_dl_pattern_100_0_13(self):
+ self.power_tel_traffic_test()
+
+ def test_umts_traffic_r_99_band_4_pul_edge_direction_dl_pattern_100_0_14(self):
+ self.power_tel_traffic_test()
+
+ def test_umts_traffic_r_7_band_4_pul_edge_direction_ul_pattern_0_100_15(self):
+ self.power_tel_traffic_test()
+
+ def test_umts_traffic_r_99_band_4_pul_edge_direction_ul_pattern_0_100_16(self):
+ self.power_tel_traffic_test()
+
+
+class PowerTelTraffic_GSM_Test(PowerTelTrafficTest):
+ def test_gsm_traffic_band_1900_gprs_pul_edge_direction_ul_pattern_0_100_slots_1_4_1(self):
+ self.power_tel_traffic_test()
+
+ def test_gsm_traffic_band_1900_gprs_pul_weak_direction_ul_pattern_0_100_slots_1_4_2(self):
+ self.power_tel_traffic_test()
+
+ def test_gsm_traffic_band_1900_gprs_pul_medium_direction_ul_pattern_0_100_slots_1_4_3(self):
+ self.power_tel_traffic_test()
+
+ def test_gsm_traffic_band_1900_gprs_pul_excellent_direction_ul_pattern_0_100_slots_1_4_4(self):
+ self.power_tel_traffic_test()
+
+ def test_gsm_traffic_band_1900_edge_pul_excellent_direction_ul_pattern_0_100_slots_1_4_5(self):
+ self.power_tel_traffic_test()
+
+ def test_gsm_traffic_band_850_edge_pul_excellent_direction_ul_pattern_0_100_slots_1_4_6(self):
+ self.power_tel_traffic_test()
+
+ def test_gsm_traffic_band_900_edge_pul_excellent_direction_ul_pattern_0_100_slots_1_4_7(self):
+ self.power_tel_traffic_test()
+
+ def test_gsm_traffic_band_1800_edge_pul_excellent_direction_ul_pattern_0_100_slots_1_4_8(self):
+ self.power_tel_traffic_test()
\ No newline at end of file
diff --git a/acts/tests/google/power/tel/lab/PowerTelTestplanHotspotTest.py b/acts/tests/google/power/tel/lab/PowerTelTestplanHotspotTest.py
new file mode 100644
index 0000000..d15abb5
--- /dev/null
+++ b/acts/tests/google/power/tel/lab/PowerTelTestplanHotspotTest.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python3.4
+#
+# Copyright 2018 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the 'License');
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an 'AS IS' BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from PowerTelHotspotTest import PowerTelHotspotTest
+
+
+class PowerTelHotspot_LTE_Test(PowerTelHotspotTest):
+
+ def test_lte_hotspot_band_2_pdl_excellent_pul_low_bw_14_tm_1_mimo_1x1_scheduling_static_direction_dl_pattern_100_0_wifiband_5g_1(self):
+ self.power_tel_tethering_test()
+
+ def test_lte_hotspot_band_13_pdl_excellent_pul_high_bw_10_tm_4_mimo_2x2_scheduling_static_direction_ul_pattern_0_100_wifiband_5g_4(self):
+ self.power_tel_tethering_test()
+
+ def test_lte_hotspot_band_13_pdl_excellent_pul_high_bw_10_tm_4_mimo_2x2_scheduling_static_direction_dl_pattern_100_0_wifiband_5g_5(self):
+ self.power_tel_tethering_test()
+
+ def test_lte_hotspot_band_7_pdl_excellent_pul_max_bw_20_tm_4_mimo_2x2_scheduling_static_direction_dl_pattern_100_0_wifiband_2g_6(self):
+ self.power_tel_tethering_test()
+
+ def test_lte_hotspot_band_3_pdl_excellent_pul_low_bw_10_tm_1_mimo_2x2_scheduling_static_direction_dl_pattern_100_0_wifiband_5g_9(self):
+ self.power_tel_tethering_test()
+
+ def test_lte_hotspot_band_3_pdl_excellent_pul_low_bw_10_tm_1_mimo_2x2_scheduling_static_direction_dlul_pattern_50_50_wifiband_2g_10(self):
+ self.power_tel_tethering_test()
+
+ def test_lte_hotspot_band_2_pdl_excellent_pul_max_bw_20_tm_1_mimo_1x1_scheduling_static_direction_dl_pattern_100_0_wifiband_2g_11(self):
+ self.power_tel_tethering_test()
+
+ def test_lte_hotspot_band_12_pdl_excellent_pul_medium_bw_5_tm_1_mimo_1x1_scheduling_static_direction_dlul_pattern_50_50_wifiband_5g_13(self):
+ self.power_tel_tethering_test()
+
+ def test_lte_hotspot_band_12_pdl_excellent_pul_medium_bw_5_tm_4_mimo_2x2_scheduling_static_direction_ul_pattern_0_100_wifiband_5g_14(self):
+ self.power_tel_tethering_test()
+
+ def test_lte_hotspot_band_5_pdl_excellent_pul_low_bw_3_tm_1_mimo_1x1_scheduling_static_direction_ul_pattern_0_100_wifiband_5g_15(self):
+ self.power_tel_tethering_test()
diff --git a/acts/tests/google/power/tel/lab/PowerTelTrafficTest.py b/acts/tests/google/power/tel/lab/PowerTelTrafficTest.py
index c84d871..b34089c 100644
--- a/acts/tests/google/power/tel/lab/PowerTelTrafficTest.py
+++ b/acts/tests/google/power/tel/lab/PowerTelTrafficTest.py
@@ -18,7 +18,7 @@
import scapy.all as scapy
-import asserts
+from acts import asserts
from acts.test_utils.power import IperfHelper as IPH
from acts.test_utils.power import PowerCellularLabBaseTest as PWCEL
from acts.test_utils.wifi import wifi_power_test_utils as wputils
@@ -374,9 +374,9 @@
for pw in sweep_range:
if self.sweep == self.PARAM_SWEEP_DOWNLINK:
- self.simulation.set_downlink_rx_power(pw)
+ self.simulation.set_downlink_rx_power(self.simulation.bts1, pw)
elif self.sweep == self.PARAM_SWEEP_UPLINK:
- self.simulation.set_uplink_tx_power(pw)
+ self.simulation.set_uplink_tx_power(self.simulation.bts1, pw)
i, t = self.power_tel_traffic_test()
self.log.info("---------------------")
diff --git a/acts/tests/google/power/wifi/PowerWiFimulticastTest.py b/acts/tests/google/power/wifi/PowerWiFimulticastTest.py
index f43f6a5..cdc75b0 100644
--- a/acts/tests/google/power/wifi/PowerWiFimulticastTest.py
+++ b/acts/tests/google/power/wifi/PowerWiFimulticastTest.py
@@ -82,6 +82,49 @@
packet = pkt_gen.generate(self.ipv4_dst_fake)
self.sendPacketAndMeasure(packet)
+ @test_tracker_info(uuid='dd3ff80d-97ce-4408-92f8-f2c72ce8d79c')
+ def test_screen_OFF_band_5g_unicast_invalid_ip_arp_request(self):
+ self.set_connection()
+ self.pkt_gen_config = wputils.create_pkt_config(self)
+ pkt_gen = pkt_utils.ArpGenerator(**self.pkt_gen_config)
+ packet = pkt_gen.generate(
+ ip_dst='0.0.0.0', eth_dst=self.pkt_gen_config['dst_mac'])
+ self.sendPacketAndMeasure(packet)
+
+ @test_tracker_info(uuid='5dcb16f1-725c-45de-8103-340104d60a22')
+ def test_screen_OFF_band_5g_unicast_misdirected_arp_request(self):
+ self.set_connection()
+ self.pkt_gen_config = wputils.create_pkt_config(self)
+ pkt_gen = pkt_utils.ArpGenerator(**self.pkt_gen_config)
+ packet = pkt_gen.generate(
+ ip_dst=self.ipv4_dst_fake, eth_dst=self.pkt_gen_config['dst_mac'])
+ self.sendPacketAndMeasure(packet)
+
+ @test_tracker_info(uuid='5ec4800f-a82e-4462-8b65-4fcd0b1940a2')
+ def test_screen_OFF_band_5g_unicast_invalid_src_arp_reply(self):
+ self.set_connection()
+ self.pkt_gen_config = wputils.create_pkt_config(self)
+ pkt_gen = pkt_utils.ArpGenerator(**self.pkt_gen_config)
+ packet = pkt_gen.generate(
+ op=scapy.ARP.is_at,
+ ip_src='0.0.0.0',
+ ip_dst=self.ipv4_dst_fake,
+ hwdst=self.mac_dst_fake,
+ eth_dst=self.pkt_gen_config['dst_mac'])
+ self.sendPacketAndMeasure(packet)
+
+ @test_tracker_info(uuid='6c5c0e9e-7a00-43d0-a6e8-355141467703')
+ def test_screen_OFF_band_5g_unicast_misdirected_arp_reply(self):
+ self.set_connection()
+ self.pkt_gen_config = wputils.create_pkt_config(self)
+ pkt_gen = pkt_utils.ArpGenerator(**self.pkt_gen_config)
+ packet = pkt_gen.generate(
+ op=scapy.ARP.is_at,
+ ip_dst=self.ipv4_dst_fake,
+ hwdst=self.mac_dst_fake,
+ eth_dst=self.pkt_gen_config['dst_mac'])
+ self.sendPacketAndMeasure(packet)
+
@test_tracker_info(uuid='8e534d3b-5a25-429a-a1bb-8119d7d28b5a')
def test_screen_OFF_band_5g_directed_ns(self):
self.set_connection()
@@ -196,6 +239,30 @@
packet = pkt_gen.generate()
self.sendPacketAndMeasure(packet)
+ @test_tracker_info(uuid='16dabe69-27a6-470b-a474-4774cd3e4715')
+ def test_screen_OFF_band_5g_dot3(self):
+ self.set_connection()
+ self.pkt_gen_config = wputils.create_pkt_config(self)
+ pkt_gen = pkt_utils.Dot3Generator(**self.pkt_gen_config)
+ packet = pkt_gen.generate()
+ self.sendPacketAndMeasure(packet)
+
+ @test_tracker_info(uuid='55d00670-f34b-4289-95fa-b618e509c15c')
+ def test_screen_OFF_band_5g_dot3_llc(self):
+ self.set_connection()
+ self.pkt_gen_config = wputils.create_pkt_config(self)
+ pkt_gen = pkt_utils.Dot3Generator(**self.pkt_gen_config)
+ packet = pkt_gen.generate_llc()
+ self.sendPacketAndMeasure(packet)
+
+ @test_tracker_info(uuid='75ba3435-fe63-4a21-8cbe-2f631043f632')
+ def test_screen_OFF_band_5g_dot3_snap(self):
+ self.set_connection()
+ self.pkt_gen_config = wputils.create_pkt_config(self)
+ pkt_gen = pkt_utils.Dot3Generator(**self.pkt_gen_config)
+ packet = pkt_gen.generate_snap()
+ self.sendPacketAndMeasure(packet)
+
# Test cases: screen ON
@test_tracker_info(uuid='b9550149-bf36-4f86-9b4b-6e900756a90e')
def test_screen_ON_band_5g_directed_arp(self):
diff --git a/acts/tests/google/power/wifi/PowerWiFiscanTest.py b/acts/tests/google/power/wifi/PowerWiFiscanTest.py
index 513e974..46c605e 100644
--- a/acts/tests/google/power/wifi/PowerWiFiscanTest.py
+++ b/acts/tests/google/power/wifi/PowerWiFiscanTest.py
@@ -32,20 +32,20 @@
' -e class com.google.android.platform.powertests.'
'WifiScanTest#testWifiSingleShotScan'
' com.google.android.platform.powertests/'
- 'android.test.InstrumentationTestRunner > /dev/null &' %
+ 'androidx.test.runner.AndroidJUnitRunner > /dev/null &' %
(self.mon_duration + self.mon_offset + 10))
BACKGROUND_SCAN = ('am instrument -w -r -e min_scan_count \"1\" -e '
'WifiScanTest-testWifiBackgroundScan %d -e class '
'com.google.android.platform.powertests.WifiScan'
'Test#testWifiBackgroundScan com.google.android.'
- 'platform.powertests/android.test.Instrumentation'
- 'TestRunner > /dev/null &' %
+ 'platform.powertests/androidx.test.runner.'
+ 'AndroidJUnitRunner > /dev/null &' %
(self.mon_duration + self.mon_offset + 10))
WIFI_SCAN = ('am instrument -w -r -e min_scan_count \"1\" -e '
'WifiScanTest-testWifiScan %d -e class '
'com.google.android.platform.powertests.WifiScanTest#'
'testWifiScan com.google.android.platform.powertests/'
- 'android.test.InstrumentationTestRunner > /dev/null &' %
+ 'androidx.test.runner.AndroidJUnitRunner > /dev/null &' %
(self.mon_duration + self.mon_offset + 10))
self.APK_SCAN_CMDS = {
'singleshot': SINGLE_SHOT_SCAN,
diff --git a/acts/tests/google/tel/live/TelLiveSmsTest.py b/acts/tests/google/tel/live/TelLiveSmsTest.py
index 3fac9af..f448c34 100644
--- a/acts/tests/google/tel/live/TelLiveSmsTest.py
+++ b/acts/tests/google/tel/live/TelLiveSmsTest.py
@@ -192,6 +192,8 @@
self.log, ads[0], ads[1], [("Test Message", "Basic Message Body",
None)]
]
+ if get_operator_name(self.log, ads[0]) in ["spt", "Sprint"]:
+ args.append(30)
if not mms_send_receive_verify(*args):
self.log.info("MMS send in call is suspended.")
if not mms_receive_verify_after_call_hangup(*args):
diff --git a/acts/tests/google/wifi/WifiChaosTest.py b/acts/tests/google/wifi/WifiChaosTest.py
index 8357d74..8a66dd4 100755
--- a/acts/tests/google/wifi/WifiChaosTest.py
+++ b/acts/tests/google/wifi/WifiChaosTest.py
@@ -122,10 +122,10 @@
self.dut.droid.wakeUpNow()
def on_pass(self, test_name, begin_time):
- wutils.stop_pcap(self.pcap, self.pcap_pid, True)
+ wutils.stop_pcap(self.pcap, self.pcap_procs, True)
def on_fail(self, test_name, begin_time):
- wutils.stop_pcap(self.pcap, self.pcap_pid, False)
+ wutils.stop_pcap(self.pcap, self.pcap_procs, False)
self.dut.take_bug_report(test_name, begin_time)
self.dut.cat_adb_log(test_name, begin_time)
@@ -193,8 +193,7 @@
Raises: TestFailure if the network connection fails.
"""
- for attempt in range(1):
- # TODO:(bmahadev) Change it to 5 or more attempts later.
+ for attempt in range(5):
try:
begin_time = time.time()
ssid = network[WifiEnums.SSID_KEY]
@@ -279,7 +278,7 @@
self.get_band_and_chan(ssid)
self.pcap.configure_monitor_mode(self.band, self.chan)
- self.pcap_pid = wutils.start_pcap(
+ self.pcap_procs = wutils.start_pcap(
self.pcap, self.band.lower(), self.log_path, self.test_name)
self.run_connect_disconnect(network, hostname, rpm_port, rpm_ip,
release_ap)
diff --git a/acts/tests/google/wifi/WifiCrashStressTest.py b/acts/tests/google/wifi/WifiCrashStressTest.py
index c628b6b..0c50629 100755
--- a/acts/tests/google/wifi/WifiCrashStressTest.py
+++ b/acts/tests/google/wifi/WifiCrashStressTest.py
@@ -85,7 +85,7 @@
del self.user_params["reference_networks"]
"""Helper Functions"""
- def trigger_wifi_firmware_crash(self, ad, timeout=30):
+ def trigger_wifi_firmware_crash(self, ad, timeout=15):
pre_timestamp = ad.adb.getprop("vendor.debug.ssrdump.timestamp")
ad.adb.shell(
"setprop persist.vendor.sys.modem.diag.mdlog false", ignore_status=True)
@@ -153,14 +153,13 @@
asserts.assert_true(
utils.adb_shell_ping(self.dut_client, count=10, dest_ip=dut_addr, timeout=20),
"%s ping %s failed" % (self.dut_client.serial, dut_addr))
- wutils.reset_wifi(self.dut_client)
for count in range(self.stress_count):
self.log.info("%s: %d/%d" %
(self.current_test_name, count + 1, self.stress_count))
+ wutils.reset_wifi(self.dut_client)
# Trigger firmware crash
self.trigger_wifi_firmware_crash(self.dut)
# Connect DUT to Network
- wutils.wifi_toggle_state(self.dut_client, True)
wutils.connect_to_wifi_network(self.dut_client, config, check_connectivity=False)
# Ping the DUT
server_addr = self.dut.droid.connectivityGetIPv4Addresses("wlan0")[0]
@@ -199,11 +198,11 @@
# Client connects to Softap
wutils.wifi_toggle_state(self.dut_client, True)
wutils.connect_to_wifi_network(self.dut_client, config)
- wutils.reset_wifi(self.dut_client)
- wutils.reset_wifi(self.dut)
for count in range(self.stress_count):
self.log.info("%s: %d/%d" %
(self.current_test_name, count + 1, self.stress_count))
+ wutils.reset_wifi(self.dut_client)
+ wutils.reset_wifi(self.dut)
# Trigger firmware crash
self.trigger_wifi_firmware_crash(self.dut)
wutils.connect_to_wifi_network(self.dut, self.network)
diff --git a/acts/tests/google/wifi/WifiNetworkSelectorTest.py b/acts/tests/google/wifi/WifiNetworkSelectorTest.py
index ffeb6b5..7015636 100644
--- a/acts/tests/google/wifi/WifiNetworkSelectorTest.py
+++ b/acts/tests/google/wifi/WifiNetworkSelectorTest.py
@@ -74,7 +74,7 @@
self.dut.ed.clear_all_events()
if hasattr(self, 'packet_capture'):
- self.pcap_pids = wutils.start_pcap(
+ self.pcap_procs = wutils.start_pcap(
self.packet_capture, 'dual', self.log_path, self.test_name)
def teardown_test(self):
@@ -84,11 +84,11 @@
def on_pass(self, test_name, begin_time):
if hasattr(self, 'packet_capture'):
- wutils.stop_pcap(self.packet_capture, self.pcap_pids, True)
+ wutils.stop_pcap(self.packet_capture, self.pcap_procs, True)
def on_fail(self, test_name, begin_time):
if hasattr(self, 'packet_capture'):
- wutils.stop_pcap(self.packet_capture, self.pcap_pids, False)
+ wutils.stop_pcap(self.packet_capture, self.pcap_procs, False)
self.dut.take_bug_report(test_name, begin_time)
self.dut.cat_adb_log(test_name, begin_time)