Add wifi stability tests
This CL adds tests that look at connected RSSI stability over time.
Test: Done
Bug: 65563975
Change-Id: Ieabba81cffa65f7352dac8f338fd0e39ffe6066c
(cherry picked from commit 9736351e359eda247e2e01299f181490d8b9be7d)
diff --git a/acts/tests/google/wifi/WifiRssiTest.py b/acts/tests/google/wifi/WifiRssiTest.py
index 756f1fe..384524f 100644
--- a/acts/tests/google/wifi/WifiRssiTest.py
+++ b/acts/tests/google/wifi/WifiRssiTest.py
@@ -19,6 +19,7 @@
import math
import os
import re
+import statistics
import time
from acts import asserts
from acts import base_test
@@ -60,6 +61,93 @@
def teardown_test(self):
self.iperf_server.stop()
+ def pass_fail_check_rssi_stability(self, rssi_result):
+ """Check the test result and decide if it passed or failed.
+
+ Checks the RSSI test result and fails the test if the standard
+ deviation of signal_poll_rssi is beyond the threshold defined in the
+ config file.
+
+ Args:
+ rssi_result: dict containing attenuation, rssi, and other meta
+ data. This dict is the output of self.post_process_results
+ """
+ # Save output as text file
+ test_name = self.current_test_name
+ results_file_path = "{}/{}.json".format(self.log_path,
+ self.current_test_name)
+ with open(results_file_path, 'w') as results_file:
+ json.dump(rssi_result, results_file, indent=4)
+
+ x_data = []
+ y_data = []
+ legends = []
+ std_deviations = {
+ "signal_poll_rssi": [],
+ "signal_poll_avg_rssi": [],
+ "chain_0_rssi": [],
+ "chain_1_rssi": [],
+ }
+ for data_point in rssi_result["rssi_result"]:
+ for key, val in data_point["connected_rssi"].items():
+ if type(val) == list:
+ x_data.append([
+ x * self.test_params["polling_frequency"]
+ for x in range(len(val))
+ ])
+ y_data.append(val)
+ legends.append(key)
+ std_deviations[key].append(
+ data_point["connected_rssi"]["stdev_" + key])
+ data_sets = [x_data, y_data]
+ x_label = 'Time (s)'
+ y_label = 'RSSI (dBm)'
+ fig_property = {
+ "title": test_name,
+ "x_label": x_label,
+ "y_label": y_label,
+ "linewidth": 3,
+ "markersize": 0
+ }
+ output_file_path = "{}/{}.html".format(self.log_path, test_name)
+ wputils.bokeh_plot(
+ data_sets,
+ legends,
+ fig_property,
+ shaded_region=None,
+ output_file_path=output_file_path)
+
+ test_failed = any([
+ stdev > self.test_params["stdev_tolerance"]
+ for stdev in std_deviations["signal_poll_rssi"]
+ ])
+ if test_failed:
+ asserts.fail(
+ "RSSI stability failed. Standard deviations were {0} dB "
+ "(limit {1}), per chain standard deviation [{2}, {3}] dB".
+ format([
+ float("{:.2f}".format(x))
+ for x in std_deviations["signal_poll_rssi"]
+ ], self.test_params["stdev_tolerance"], [
+ float("{:.2f}".format(x))
+ for x in std_deviations["chain_0_rssi"]
+ ], [
+ float("{:.2f}".format(x))
+ for x in std_deviations["chain_1_rssi"]
+ ]))
+ asserts.explicit_pass(
+ "RSSI stability passed. Standard deviations were {0} dB "
+ "(limit {1}), per chain standard deviation [{2}, {3}] dB".format([
+ float("{:.2f}".format(x))
+ for x in std_deviations["signal_poll_rssi"]
+ ], self.test_params["stdev_tolerance"], [
+ float("{:.2f}".format(x))
+ for x in std_deviations["chain_0_rssi"]
+ ], [
+ float("{:.2f}".format(x))
+ for x in std_deviations["chain_1_rssi"]
+ ]))
+
def pass_fail_check_rssi_vs_attenuation(self, postprocessed_results):
"""Check the test result and decide if it passed or failed.
@@ -137,7 +225,7 @@
asserts.fail(test_message)
asserts.explicit_pass(test_message)
- def post_process_results(self, rssi_result):
+ def post_process_rssi_vs_attenuation(self, rssi_result):
"""Saves plots and JSON formatted results.
Args:
@@ -152,7 +240,7 @@
results_file_path = "{}/{}.json".format(self.log_path,
self.current_test_name)
with open(results_file_path, 'w') as results_file:
- json.dump(rssi_result, results_file)
+ json.dump(rssi_result, results_file, indent=4)
# Plot and save
total_attenuation = [
att + rssi_result["fixed_attenuation"]
@@ -226,7 +314,7 @@
num_measurements: number of scans done, and RSSIs collected
Returns:
scan_rssi: dict containing the measurement results as well as the
- average scan RSSI for all BSSIDs in tracked_bssids
+ statistics of the scan RSSI for all BSSIDs in tracked_bssids
"""
scan_rssi = {}
for bssid in tracked_bssids:
@@ -252,8 +340,14 @@
if filtered_rssi_values:
scan_rssi[key]["avg_rssi"] = sum(filtered_rssi_values) / len(
filtered_rssi_values)
+ if len(filtered_rssi_values) > 1:
+ scan_rssi[key]["stdev"] = statistics.stdev(
+ filtered_rssi_values)
+ else:
+ scan_rssi[key]["stdev"] = 0
else:
scan_rssi[key]["avg_rssi"] = RSSI_ERROR_VAL
+ scan_rssi[key]["stdev"] = RSSI_ERROR_VAL
return scan_rssi
def get_connected_rssi(self,
@@ -267,7 +361,7 @@
Returns:
connected_rssi: dict containing the measurements results for
all reported RSSI values (signal_poll, per chain, etc.) and their
- averages
+ statistics
"""
connected_rssi = {
"signal_poll_rssi": [],
@@ -313,8 +407,14 @@
if filtered_rssi_values:
connected_rssi["mean_{}".format(key)] = sum(
filtered_rssi_values) / len(filtered_rssi_values)
+ if len(filtered_rssi_values) > 1:
+ connected_rssi["stdev_{}".format(key)] = statistics.stdev(
+ filtered_rssi_values)
+ else:
+ connected_rssi["stdev_{}".format(key)] = 0
else:
connected_rssi["mean_{}".format(key)] = RSSI_ERROR_VAL
+ connected_rssi["stdev_{}".format(key)] = RSSI_ERROR_VAL
return connected_rssi
def rssi_test(self, iperf_traffic, connected_measurements,
@@ -370,7 +470,8 @@
[self.attenuators[i].set_atten(0) for i in range(self.num_atten)]
return rssi_result
- def rssi_test_func(self):
+ def rssi_test_func(self, iperf_traffic, connected_measurements,
+ scan_measurements, bssids, polling_frequency):
"""Main function to test RSSI.
The function sets up the AP in the correct channel and mode
@@ -380,16 +481,7 @@
Returns:
rssi_result: dict containing rssi_results and meta data
"""
- #Initialize test parameters
- num_atten_steps = int((self.test_params["rssi_atten_stop"] -
- self.test_params["rssi_atten_start"]) /
- self.test_params["rssi_atten_step"])
- self.rssi_atten_range = [
- self.test_params["rssi_atten_start"] +
- x * self.test_params["rssi_atten_step"]
- for x in range(0, num_atten_steps)
- ]
-
+ #Initialize test settings
rssi_result = {}
# Configure AP
band = self.access_point.band_lookup_by_channel(self.channel)
@@ -418,10 +510,8 @@
rssi_result["fixed_attenuation"] = self.test_params[
"fixed_attenuation"][str(self.channel)]
rssi_result["rssi_result"] = self.rssi_test(
- self.iperf_traffic, self.test_params["connected_measurements"],
- self.test_params["scan_measurements"], [
- self.main_network[band]["BSSID"]
- ], self.test_params["polling_frequency"])
+ iperf_traffic, connected_measurements, scan_measurements, bssids,
+ polling_frequency)
self.testclass_results.append(rssi_result)
return rssi_result
@@ -429,25 +519,152 @@
""" Function that gets called for each test case of rssi_vs_atten
The function gets called in each rvr test case. The function customizes
- the rvr test based on the test name of the test that called it
+ the test based on the test name of the test that called it
"""
test_params = self.current_test_name.split("_")
self.channel = int(test_params[4][2:])
self.mode = test_params[5]
self.iperf_traffic = "ActiveTraffic" in test_params[6]
self.iperf_args = '-i 1 -t 3600 -J -R'
- rssi_result = self.rssi_test_func()
- postprocessed_results = self.post_process_results(rssi_result)
+ band = self.access_point.band_lookup_by_channel(self.channel)
+ num_atten_steps = int((self.test_params["rssi_atten_stop"] -
+ self.test_params["rssi_atten_start"]) /
+ self.test_params["rssi_atten_step"])
+ self.rssi_atten_range = [
+ self.test_params["rssi_atten_start"] +
+ x * self.test_params["rssi_atten_step"]
+ for x in range(0, num_atten_steps)
+ ]
+ rssi_result = self.rssi_test_func(
+ self.iperf_traffic, self.test_params["connected_measurements"],
+ self.test_params["scan_measurements"], [
+ self.main_network[band]["BSSID"]
+ ], self.test_params["polling_frequency"])
+ postprocessed_results = self.post_process_rssi_vs_attenuation(
+ rssi_result)
self.pass_fail_check_rssi_vs_attenuation(postprocessed_results)
def _test_rssi_stability(self):
- #TODO: Implement test that looks at RSSI stability at fixed attenuation
- pass
+ """ Function that gets called for each test case of rssi_stability
+ The function gets called in each stability test case. The function
+ customizes test based on the test name of the test that called it
+ """
+ test_params = self.current_test_name.split("_")
+ self.channel = int(test_params[3][2:])
+ self.mode = test_params[4]
+ self.iperf_traffic = "ActiveTraffic" in test_params[5]
+ self.iperf_args = '-i 1 -t 3600 -J -R'
+ band = self.access_point.band_lookup_by_channel(self.channel)
+ self.rssi_atten_range = self.test_params["stability_test_atten"]
+ connected_measurements = int(
+ self.test_params["stability_test_duration"] /
+ self.test_params["polling_frequency"])
+ rssi_result = self.rssi_test_func(
+ self.iperf_traffic, connected_measurements, 0, [
+ self.main_network[band]["BSSID"]
+ ], self.test_params["polling_frequency"])
+ self.pass_fail_check_rssi_stability(rssi_result)
-class WifiRssi_2GHz_ActiveTraffic_Test(WifiRssiTest):
- def __init__(self, controllers):
- base_test.BaseTestClass.__init__(self, controllers)
+ @test_tracker_info(uuid='519689b8-0a3c-4fd9-9227-fd7962d0f1a0')
+ def test_rssi_stability_ch1_VHT20_ActiveTraffic(self):
+ self._test_rssi_stability()
+
+ @test_tracker_info(uuid='23eca2ab-d0b4-4730-9f32-ec2d901ae493')
+ def test_rssi_stability_ch2_VHT20_ActiveTraffic(self):
+ self._test_rssi_stability()
+
+ @test_tracker_info(uuid='63d340c0-dcf9-4e14-87bd-a068a59836b2')
+ def test_rssi_stability_ch3_VHT20_ActiveTraffic(self):
+ self._test_rssi_stability()
+
+ @test_tracker_info(uuid='ddbe88d8-be20-40eb-8f29-55049e3fef28')
+ def test_rssi_stability_ch4_VHT20_ActiveTraffic(self):
+ self._test_rssi_stability()
+
+ @test_tracker_info(uuid='9c06304e-2b60-4619-8fb3-73fd2cb4b854')
+ def test_rssi_stability_ch5_VHT20_ActiveTraffic(self):
+ self._test_rssi_stability()
+
+ @test_tracker_info(uuid='74b656ca-132e-4d66-9584-560287081607')
+ def test_rssi_stability_ch6_VHT20_ActiveTraffic(self):
+ self._test_rssi_stability()
+
+ @test_tracker_info(uuid='23b5f19a-539b-4908-a197-06ce505d3d23')
+ def test_rssi_stability_ch7_VHT20_ActiveTraffic(self):
+ self._test_rssi_stability()
+
+ @test_tracker_info(uuid='e7b85167-f4c4-4adb-a111-04d8a5f10e1a')
+ def test_rssi_stability_ch8_VHT20_ActiveTraffic(self):
+ self._test_rssi_stability()
+
+ @test_tracker_info(uuid='2a0a9393-4b68-4c08-8787-3f35d1a8458b')
+ def test_rssi_stability_ch9_VHT20_ActiveTraffic(self):
+ self._test_rssi_stability()
+
+ @test_tracker_info(uuid='069c7acf-3e7e-4298-91cb-d292c6025ae1')
+ def test_rssi_stability_ch10_VHT20_ActiveTraffic(self):
+ self._test_rssi_stability()
+
+ @test_tracker_info(uuid='95c5a27c-1dea-47a4-a1c5-edf955545f12')
+ def test_rssi_stability_ch11_VHT20_ActiveTraffic(self):
+ self._test_rssi_stability()
+
+ @test_tracker_info(uuid='8aeab023-a096-4fbe-80dd-fd01466f9fac')
+ def test_rssi_stability_ch36_VHT20_ActiveTraffic(self):
+ self._test_rssi_stability()
+
+ @test_tracker_info(uuid='872fed9f-d0bb-4a7b-a2a7-bf8df7740b2d')
+ def test_rssi_stability_ch36_VHT40_ActiveTraffic(self):
+ self._test_rssi_stability()
+
+ @test_tracker_info(uuid='27395fd1-e286-473a-b98e-5a50db2a598a')
+ def test_rssi_stability_ch36_VHT80_ActiveTraffic(self):
+ self._test_rssi_stability()
+
+ @test_tracker_info(uuid='6f6b25e3-1a1e-4a61-930a-1d0aa25ba900')
+ def test_rssi_stability_ch40_VHT20_ActiveTraffic(self):
+ self._test_rssi_stability()
+
+ @test_tracker_info(uuid='c6717da7-855c-4c6e-a6e2-ee42b8feaaab')
+ def test_rssi_stability_ch44_VHT20_ActiveTraffic(self):
+ self._test_rssi_stability()
+
+ @test_tracker_info(uuid='2e34f735-079c-4619-9e74-b96dc8d0597f')
+ def test_rssi_stability_ch44_VHT40_ActiveTraffic(self):
+ self._test_rssi_stability()
+
+ @test_tracker_info(uuid='d543c019-1ff5-41d4-9b37-ccdc593f3edd')
+ def test_rssi_stability_ch48_VHT20_ActiveTraffic(self):
+ self._test_rssi_stability()
+
+ @test_tracker_info(uuid='2bb08914-36b2-4f58-9b3e-c3f3f4fac8ab')
+ def test_rssi_stability_ch149_VHT20_ActiveTraffic(self):
+ self._test_rssi_stability()
+
+ @test_tracker_info(uuid='e2f585f5-7811-4570-b987-23da301eb75d')
+ def test_rssi_stability_ch149_VHT40_ActiveTraffic(self):
+ self._test_rssi_stability()
+
+ @test_tracker_info(uuid='f3e74d5b-73f6-4723-abf3-c9c147db08e3')
+ def test_rssi_stability_ch149_VHT80_ActiveTraffic(self):
+ self._test_rssi_stability()
+
+ @test_tracker_info(uuid='06503ed0-baf3-4cd1-ac5e-4124e3c7f52f')
+ def test_rssi_stability_ch153_VHT20_ActiveTraffic(self):
+ self._test_rssi_stability()
+
+ @test_tracker_info(uuid='0cf8286f-a919-4e29-a9f2-e7738a4afe8f')
+ def test_rssi_stability_ch157_VHT20_ActiveTraffic(self):
+ self._test_rssi_stability()
+
+ @test_tracker_info(uuid='f9a0165c-468b-4096-8f4b-cc80bae564a0')
+ def test_rssi_stability_ch157_VHT40_ActiveTraffic(self):
+ self._test_rssi_stability()
+
+ @test_tracker_info(uuid='4b74dd46-4190-4556-8ad8-c55808e9e847')
+ def test_rssi_stability_ch161_VHT20_ActiveTraffic(self):
+ self._test_rssi_vs_atten()
@test_tracker_info(uuid='ae54b7cc-d76d-4460-8dcc-2c439265c7c9')
def test_rssi_vs_atten_ch1_VHT20_ActiveTraffic(self):
@@ -493,11 +710,6 @@
def test_rssi_vs_atten_ch11_VHT20_ActiveTraffic(self):
self._test_rssi_vs_atten()
-
-class WifiRssi_5GHz_ActiveTraffic_Test(WifiRssiTest):
- def __init__(self, controllers):
- base_test.BaseTestClass.__init__(self, controllers)
-
@test_tracker_info(uuid='a33a93ac-604a-414f-ae96-42dffbe59a93')
def test_rssi_vs_atten_ch36_VHT20_ActiveTraffic(self):
self._test_rssi_vs_atten()
@@ -553,3 +765,63 @@
@test_tracker_info(uuid='581b5794-239e-4d1c-b0ce-7c6dc5bd373f')
def test_rssi_vs_atten_ch161_VHT20_ActiveTraffic(self):
self._test_rssi_vs_atten()
+
+
+class WifiRssi_2GHz_ActiveTraffic_Test(WifiRssiTest):
+ def __init__(self, controllers):
+ base_test.BaseTestClass.__init__(self, controllers)
+ self.tests = ("test_rssi_stability_ch1_VHT20_ActiveTraffic",
+ "test_rssi_stability_ch2_VHT20_ActiveTraffic",
+ "test_rssi_stability_ch3_VHT20_ActiveTraffic",
+ "test_rssi_stability_ch4_VHT20_ActiveTraffic",
+ "test_rssi_stability_ch5_VHT20_ActiveTraffic",
+ "test_rssi_stability_ch6_VHT20_ActiveTraffic",
+ "test_rssi_stability_ch7_VHT20_ActiveTraffic",
+ "test_rssi_stability_ch8_VHT20_ActiveTraffic",
+ "test_rssi_stability_ch9_VHT20_ActiveTraffic",
+ "test_rssi_stability_ch10_VHT20_ActiveTraffic",
+ "test_rssi_stability_ch11_VHT20_ActiveTraffic",
+ "test_rssi_vs_atten_ch1_VHT20_ActiveTraffic",
+ "test_rssi_vs_atten_ch2_VHT20_ActiveTraffic",
+ "test_rssi_vs_atten_ch3_VHT20_ActiveTraffic",
+ "test_rssi_vs_atten_ch4_VHT20_ActiveTraffic",
+ "test_rssi_vs_atten_ch5_VHT20_ActiveTraffic",
+ "test_rssi_vs_atten_ch6_VHT20_ActiveTraffic",
+ "test_rssi_vs_atten_ch7_VHT20_ActiveTraffic",
+ "test_rssi_vs_atten_ch8_VHT20_ActiveTraffic",
+ "test_rssi_vs_atten_ch9_VHT20_ActiveTraffic",
+ "test_rssi_vs_atten_ch10_VHT20_ActiveTraffic",
+ "test_rssi_vs_atten_ch11_VHT20_ActiveTraffic")
+
+
+class WifiRssi_5GHz_ActiveTraffic_Test(WifiRssiTest):
+ def __init__(self, controllers):
+ base_test.BaseTestClass.__init__(self, controllers)
+ self.tests = ("test_rssi_stability_ch36_VHT20_ActiveTraffic",
+ "test_rssi_stability_ch36_VHT40_ActiveTraffic",
+ "test_rssi_stability_ch36_VHT80_ActiveTraffic",
+ "test_rssi_stability_ch40_VHT20_ActiveTraffic",
+ "test_rssi_stability_ch44_VHT20_ActiveTraffic",
+ "test_rssi_stability_ch44_VHT40_ActiveTraffic",
+ "test_rssi_stability_ch48_VHT20_ActiveTraffic",
+ "test_rssi_stability_ch149_VHT20_ActiveTraffic",
+ "test_rssi_stability_ch149_VHT40_ActiveTraffic",
+ "test_rssi_stability_ch149_VHT80_ActiveTraffic",
+ "test_rssi_stability_ch153_VHT20_ActiveTraffic",
+ "test_rssi_stability_ch157_VHT20_ActiveTraffic",
+ "test_rssi_stability_ch157_VHT40_ActiveTraffic",
+ "test_rssi_stability_ch161_VHT20_ActiveTraffic",
+ "test_rssi_vs_atten_ch36_VHT20_ActiveTraffic",
+ "test_rssi_vs_atten_ch36_VHT40_ActiveTraffic",
+ "test_rssi_vs_atten_ch36_VHT80_ActiveTraffic",
+ "test_rssi_vs_atten_ch40_VHT20_ActiveTraffic",
+ "test_rssi_vs_atten_ch44_VHT20_ActiveTraffic",
+ "test_rssi_vs_atten_ch44_VHT40_ActiveTraffic",
+ "test_rssi_vs_atten_ch48_VHT20_ActiveTraffic",
+ "test_rssi_vs_atten_ch149_VHT20_ActiveTraffic",
+ "test_rssi_vs_atten_ch149_VHT40_ActiveTraffic",
+ "test_rssi_vs_atten_ch149_VHT80_ActiveTraffic",
+ "test_rssi_vs_atten_ch153_VHT20_ActiveTraffic",
+ "test_rssi_vs_atten_ch157_VHT20_ActiveTraffic",
+ "test_rssi_vs_atten_ch157_VHT40_ActiveTraffic",
+ "test_rssi_vs_atten_ch161_VHT20_ActiveTraffic")