• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3.4
2#
3#   Copyright 2017 - The Android Open Source Project
4#
5#   Licensed under the Apache License, Version 2.0 (the "License");
6#   you may not use this file except in compliance with the License.
7#   You may obtain a copy of the License at
8#
9#       http://www.apache.org/licenses/LICENSE-2.0
10#
11#   Unless required by applicable law or agreed to in writing, software
12#   distributed under the License is distributed on an "AS IS" BASIS,
13#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14#   See the License for the specific language governing permissions and
15#   limitations under the License.
16
17import collections
18import json
19import logging
20import math
21import os
22import time
23from acts import asserts
24from acts import base_test
25from acts import utils
26from acts.controllers import iperf_server as ipf
27from acts.metrics.loggers.blackbox import BlackboxMetricLogger
28from acts.test_decorators import test_tracker_info
29from acts.test_utils.wifi import wifi_performance_test_utils as wputils
30from acts.test_utils.wifi import wifi_retail_ap as retail_ap
31from acts.test_utils.wifi import wifi_test_utils as wutils
32
33
34class WifiRvrTest(base_test.BaseTestClass):
35    """Class to test WiFi rate versus range.
36
37    This class implements WiFi rate versus range tests on single AP single STA
38    links. The class setups up the AP in the desired configurations, configures
39    and connects the phone to the AP, and runs iperf throughput test while
40    sweeping attenuation. For an example config file to run this test class see
41    example_connectivity_performance_ap_sta.json.
42    """
43
44    TEST_TIMEOUT = 5
45    SHORT_SLEEP = 1
46    RSSI_POLL_INTERVAL = 1
47    MAX_CONSECUTIVE_ZEROS = 3
48
49    def __init__(self, controllers):
50        base_test.BaseTestClass.__init__(self, controllers)
51        self.failure_count_metric = BlackboxMetricLogger.for_test_case(
52            metric_name='failure_count')
53
54    def setup_class(self):
55        """Initializes common test hardware and parameters.
56
57        This function initializes hardwares and compiles parameters that are
58        common to all tests in this class.
59        """
60        self.client_dut = self.android_devices[-1]
61        req_params = [
62            "RetailAccessPoints", "rvr_test_params", "testbed_params"
63        ]
64        opt_params = ["main_network", "golden_files_list"]
65        self.unpack_userparams(req_params, opt_params)
66        self.testclass_params = self.rvr_test_params
67        self.num_atten = self.attenuators[0].instrument.num_atten
68        self.iperf_server = self.iperf_servers[0]
69        self.iperf_client = self.iperf_clients[0]
70        self.access_points = retail_ap.create(self.RetailAccessPoints)
71        self.access_point = self.access_points[0]
72        self.log.info("Access Point Configuration: {}".format(
73            self.access_point.ap_settings))
74        self.log_path = os.path.join(logging.log_path, "results")
75        utils.create_dir(self.log_path)
76        if not hasattr(self, "golden_files_list"):
77            self.golden_files_list = [
78                os.path.join(self.testbed_params["golden_results_path"],
79                             file) for file in os.listdir(
80                                 self.testbed_params["golden_results_path"])
81            ]
82        self.testclass_results = []
83
84        # Turn WiFi ON
85        for dev in self.android_devices:
86            wutils.wifi_toggle_state(dev, True)
87
88    def teardown_test(self):
89        self.iperf_server.stop()
90
91    def teardown_class(self):
92        # Turn WiFi OFF
93        for dev in self.android_devices:
94            wutils.wifi_toggle_state(dev, False)
95        self.process_testclass_results()
96
97    def process_testclass_results(self):
98        """Saves plot with all test results to enable comparison."""
99        # Plot and save all results
100        plot_data = collections.OrderedDict()
101        plots = []
102        for result in self.testclass_results:
103            testcase_params = self.parse_test_params(result["test_name"])
104            plot_id = (testcase_params["channel"], testcase_params["mode"])
105            if plot_id not in plot_data:
106                plot_data[plot_id] = {"x_data": [], "y_data": [], "legend": []}
107            total_attenuation = [
108                att + result["fixed_attenuation"]
109                for att in result["attenuation"]
110            ]
111            plot_data[plot_id]["x_data"].append(total_attenuation)
112            plot_data[plot_id]["y_data"].append(result["throughput_receive"])
113            plot_data[plot_id]["legend"].append(result["test_name"])
114        for plot_id, plot_data in plot_data.items():
115            data_set = [plot_data["x_data"], plot_data["y_data"]]
116            fig_property = {
117                "title": "Channel {} - {}".format(plot_id[0], plot_id[1]),
118                "x_label": 'Attenuation (dB)',
119                "y_label": 'Throughput (Mbps)',
120                "linewidth": 3,
121                "markersize": 10
122            }
123            plots.append(
124                wputils.bokeh_plot(
125                    data_set,
126                    plot_data["legend"],
127                    fig_property,
128                    shaded_region=None))
129        output_file_path = os.path.join(self.log_path, 'results.html')
130        wputils.save_bokeh_plots(plots, output_file_path)
131
132    def pass_fail_check(self, rvr_result):
133        """Check the test result and decide if it passed or failed.
134
135        Checks the RvR test result and compares to a throughput limites for
136        the same configuration. The pass/fail tolerances are provided in the
137        config file.
138
139        Args:
140            rvr_result: dict containing attenuation, throughput and other meta
141            data
142        """
143        try:
144            throughput_limits = self.compute_throughput_limits(rvr_result)
145        except:
146            asserts.fail("Test failed: Golden file not found")
147
148        failure_count = 0
149        for idx, current_throughput in enumerate(
150                rvr_result["throughput_receive"]):
151            current_att = rvr_result["attenuation"][idx] + rvr_result["fixed_attenuation"]
152            if (current_throughput < throughput_limits["lower_limit"][idx]
153                    or current_throughput >
154                    throughput_limits["upper_limit"][idx]):
155                failure_count = failure_count + 1
156                self.log.info(
157                    "Throughput at {}dB attenuation is beyond limits. "
158                    "Throughput is {} Mbps. Expected within [{}, {}] Mbps.".
159                    format(current_att, current_throughput,
160                           throughput_limits["lower_limit"][idx],
161                           throughput_limits["upper_limit"][idx]))
162        self.failure_count_metric.metric_value = failure_count
163        if failure_count >= self.testclass_params["failure_count_tolerance"]:
164            asserts.fail("Test failed. Found {} points outside limits.".format(
165                failure_count))
166        asserts.explicit_pass(
167            "Test passed. Found {} points outside throughput limits.".format(
168                failure_count))
169
170    def compute_throughput_limits(self, rvr_result):
171        """Compute throughput limits for current test.
172
173        Checks the RvR test result and compares to a throughput limites for
174        the same configuration. The pass/fail tolerances are provided in the
175        config file.
176
177        Args:
178            rvr_result: dict containing attenuation, throughput and other meta
179            data
180        Returns:
181            throughput_limits: dict containing attenuation and throughput limit data
182        """
183        test_name = self.current_test_name
184        golden_path = next(file_name for file_name in self.golden_files_list
185                           if test_name in file_name)
186        with open(golden_path, 'r') as golden_file:
187            golden_results = json.load(golden_file)
188            golden_attenuation = [
189                att + golden_results["fixed_attenuation"]
190                for att in golden_results["attenuation"]
191            ]
192        attenuation = []
193        lower_limit = []
194        upper_limit = []
195        for idx, current_throughput in enumerate(
196                rvr_result["throughput_receive"]):
197            current_att = rvr_result["attenuation"][idx] + rvr_result["fixed_attenuation"]
198            att_distances = [
199                abs(current_att - golden_att)
200                for golden_att in golden_attenuation
201            ]
202            sorted_distances = sorted(
203                enumerate(att_distances), key=lambda x: x[1])
204            closest_indeces = [dist[0] for dist in sorted_distances[0:3]]
205            closest_throughputs = [
206                golden_results["throughput_receive"][index]
207                for index in closest_indeces
208            ]
209            closest_throughputs.sort()
210
211            attenuation.append(current_att)
212            lower_limit.append(
213                max(closest_throughputs[0] -
214                    max(self.testclass_params["abs_tolerance"],
215                        closest_throughputs[0] *
216                        self.testclass_params["pct_tolerance"] / 100), 0))
217            upper_limit.append(closest_throughputs[-1] + max(
218                self.testclass_params["abs_tolerance"], closest_throughputs[-1]
219                * self.testclass_params["pct_tolerance"] / 100))
220        throughput_limits = {
221            "attenuation": attenuation,
222            "lower_limit": lower_limit,
223            "upper_limit": upper_limit
224        }
225        return throughput_limits
226
227    def process_test_results(self, rvr_result):
228        """Saves plots and JSON formatted results.
229
230        Args:
231            rvr_result: dict containing attenuation, throughput and other meta
232            data
233        """
234        # Save output as text file
235        test_name = self.current_test_name
236        results_file_path = "{}/{}.json".format(self.log_path,
237                                                self.current_test_name)
238        with open(results_file_path, 'w') as results_file:
239            json.dump(rvr_result, results_file, indent=4)
240        # Plot and save
241        legends = [self.current_test_name]
242        x_label = 'Attenuation (dB)'
243        y_label = 'Throughput (Mbps)'
244        total_attenuation = [
245            att + rvr_result["fixed_attenuation"]
246            for att in rvr_result["attenuation"]
247        ]
248        data_sets = [[total_attenuation], [rvr_result["throughput_receive"]]]
249        fig_property = {
250            "title": test_name,
251            "x_label": x_label,
252            "y_label": y_label,
253            "linewidth": 3,
254            "markersize": 10
255        }
256        try:
257            golden_path = next(file_name
258                               for file_name in self.golden_files_list
259                               if test_name in file_name)
260            with open(golden_path, 'r') as golden_file:
261                golden_results = json.load(golden_file)
262            legends.insert(0, "Golden Results")
263            golden_attenuation = [
264                att + golden_results["fixed_attenuation"]
265                for att in golden_results["attenuation"]
266            ]
267            data_sets[0].insert(0, golden_attenuation)
268            data_sets[1].insert(0, golden_results["throughput_receive"])
269            throughput_limits = self.compute_throughput_limits(rvr_result)
270            shaded_region = {
271                "x_vector": throughput_limits["attenuation"],
272                "lower_limit": throughput_limits["lower_limit"],
273                "upper_limit": throughput_limits["upper_limit"]
274            }
275        except:
276            shaded_region = None
277            self.log.warning("ValueError: Golden file not found")
278        output_file_path = "{}/{}.html".format(self.log_path, test_name)
279        wputils.bokeh_plot(data_sets, legends, fig_property, shaded_region,
280                           output_file_path)
281
282    def run_rvr_test(self, testcase_params):
283        """Test function to run RvR.
284
285        The function runs an RvR test in the current device/AP configuration.
286        Function is called from another wrapper function that sets up the
287        testbed for the RvR test
288
289        Args:
290            testcase_params: dict containing test-specific parameters
291        Returns:
292            rvr_result: dict containing rvr_results and meta data
293        """
294        self.log.info("Start running RvR")
295        zero_counter = 0
296        throughput = []
297        rssi = []
298        for atten in testcase_params["atten_range"]:
299            # Set Attenuation
300            for attenuator in self.attenuators:
301                attenuator.set_atten(atten, strict=False)
302            # Start iperf session
303            self.iperf_server.start(tag=str(atten))
304            rssi_future = wputils.get_connected_rssi_nb(
305                self.client_dut, testcase_params["iperf_duration"] - 1, 1, 1)
306            client_output_path = self.iperf_client.start(
307                testcase_params["iperf_server_address"],
308                testcase_params["iperf_args"], str(atten),
309                testcase_params["iperf_duration"] + self.TEST_TIMEOUT)
310            server_output_path = self.iperf_server.stop()
311            current_rssi = rssi_future.result()["signal_poll_rssi"]["mean"]
312            rssi.append(current_rssi)
313            # Parse and log result
314            if testcase_params["use_client_output"]:
315                iperf_file = client_output_path
316            else:
317                iperf_file = server_output_path
318            try:
319                iperf_result = ipf.IPerfResult(iperf_file)
320                curr_throughput = (math.fsum(iperf_result.instantaneous_rates[
321                    self.testclass_params["iperf_ignored_interval"]:-1]) / len(
322                        iperf_result.instantaneous_rates[self.testclass_params[
323                            "iperf_ignored_interval"]:-1])) * 8 * (1.024**2)
324            except:
325                self.log.warning(
326                    "ValueError: Cannot get iperf result. Setting to 0")
327                curr_throughput = 0
328            throughput.append(curr_throughput)
329            self.log.info(
330                "Throughput at {0:.2f} dB is {1:.2f} Mbps. RSSI = {2:.2f}".
331                format(atten, curr_throughput, current_rssi))
332            if curr_throughput == 0:
333                zero_counter = zero_counter + 1
334            else:
335                zero_counter = 0
336            if zero_counter == self.MAX_CONSECUTIVE_ZEROS:
337                self.log.info(
338                    "Throughput stable at 0 Mbps. Stopping test now.")
339                throughput.extend(
340                    [0] *
341                    (len(testcase_params["atten_range"]) - len(throughput)))
342                break
343        for attenuator in self.attenuators:
344            attenuator.set_atten(0, strict=False)
345        # Compile test result and meta data
346        rvr_result = collections.OrderedDict()
347        rvr_result["test_name"] = self.current_test_name
348        rvr_result["ap_settings"] = self.access_point.ap_settings.copy()
349        rvr_result["fixed_attenuation"] = self.testbed_params[
350            "fixed_attenuation"][str(testcase_params["channel"])]
351        rvr_result["attenuation"] = list(testcase_params["atten_range"])
352        rvr_result["rssi"] = rssi
353        rvr_result["throughput_receive"] = throughput
354        return rvr_result
355
356    def setup_ap(self, testcase_params):
357        """Sets up the access point in the configuration required by the test.
358
359        Args:
360            testcase_params: dict containing AP and other test params
361        """
362        band = self.access_point.band_lookup_by_channel(
363            testcase_params["channel"])
364        if "2G" in band:
365            frequency = wutils.WifiEnums.channel_2G_to_freq[testcase_params[
366                "channel"]]
367        else:
368            frequency = wutils.WifiEnums.channel_5G_to_freq[testcase_params[
369                "channel"]]
370        if frequency in wutils.WifiEnums.DFS_5G_FREQUENCIES:
371            self.access_point.set_region(self.testbed_params["DFS_region"])
372        else:
373            self.access_point.set_region(self.testbed_params["default_region"])
374        self.access_point.set_channel(band, testcase_params["channel"])
375        self.access_point.set_bandwidth(band, testcase_params["mode"])
376        self.log.info("Access Point Configuration: {}".format(
377            self.access_point.ap_settings))
378
379    def setup_dut(self, testcase_params):
380        """Sets up the DUT in the configuration required by the test.
381
382        Args:
383            testcase_params: dict containing AP and other test params
384        """
385        band = self.access_point.band_lookup_by_channel(
386            testcase_params["channel"])
387        wutils.reset_wifi(self.client_dut)
388        self.client_dut.droid.wifiSetCountryCode(
389            self.testclass_params["country_code"])
390        self.main_network[band]["channel"] = testcase_params["channel"]
391        wutils.wifi_connect(
392            self.client_dut,
393            self.main_network[band],
394            num_of_tries=5,
395            check_connectivity=False)
396        self.dut_ip = self.client_dut.droid.connectivityGetIPv4Addresses(
397            'wlan0')[0]
398
399    def setup_rvr_test(self, testcase_params):
400        """Function that gets devices ready for the test.
401
402        Args:
403            testcase_params: dict containing test-specific parameters
404        """
405        # Configure AP
406        self.setup_ap(testcase_params)
407        # Set attenuator to 0 dB
408        for attenuator in self.attenuators:
409            attenuator.set_atten(0, strict=False)
410        # Reset, configure, and connect DUT
411        self.setup_dut(testcase_params)
412        # Get iperf_server address
413        if isinstance(self.iperf_server, ipf.IPerfServerOverAdb):
414            testcase_params["iperf_server_address"] = self.dut_ip
415        else:
416            testcase_params["iperf_server_address"] = self.testbed_params[
417                "iperf_server_address"]
418
419    def parse_test_params(self, test_name):
420        """Function that generates test params based on the test name."""
421        test_name_params = test_name.split("_")
422        testcase_params = collections.OrderedDict()
423        testcase_params["channel"] = int(test_name_params[4][2:])
424        testcase_params["mode"] = test_name_params[5]
425        num_atten_steps = int((self.testclass_params["atten_stop"] -
426                               self.testclass_params["atten_start"]) /
427                              self.testclass_params["atten_step"])
428        testcase_params["atten_range"] = [
429            self.testclass_params["atten_start"] +
430            x * self.testclass_params["atten_step"]
431            for x in range(0, num_atten_steps)
432        ]
433        testcase_params["iperf_args"] = '-i 1 -t {} -J '.format(
434            self.testclass_params["iperf_duration"])
435        if test_name_params[2] == "UDP":
436            testcase_params[
437                "iperf_args"] = testcase_params["iperf_args"] + "-u -b {}".format(
438                    self.testclass_params["UDP_rates"][testcase_params["mode"]])
439        if (test_name_params[3] == "DL"
440                and not isinstance(self.iperf_server, ipf.IPerfServerOverAdb)
441            ) or (test_name_params[3] == "UL"
442                  and isinstance(self.iperf_server, ipf.IPerfServerOverAdb)):
443            testcase_params[
444                "iperf_args"] = testcase_params["iperf_args"] + ' -R'
445            testcase_params["use_client_output"] = True
446        else:
447            testcase_params["use_client_output"] = False
448        return testcase_params
449
450    def _test_rvr(self):
451        """ Function that gets called for each test case
452
453        The function gets called in each rvr test case. The function customizes
454        the rvr test based on the test name of the test that called it
455        """
456        # Compile test parameters from config and test name
457        testcase_params = self.parse_test_params(self.current_test_name)
458        testcase_params.update(self.testclass_params)
459
460        # Prepare devices and run test
461        self.setup_rvr_test(testcase_params)
462        rvr_result = self.run_rvr_test(testcase_params)
463
464        # Post-process results
465        self.testclass_results.append(rvr_result)
466        self.process_test_results(rvr_result)
467        self.pass_fail_check(rvr_result)
468
469    #Test cases
470    @test_tracker_info(uuid='e7586217-3739-44a4-a87b-d790208b04b9')
471    def test_rvr_TCP_DL_ch1_VHT20(self):
472        self._test_rvr()
473
474    @test_tracker_info(uuid='06b3e979-255c-482f-b570-d347fba048b6')
475    def test_rvr_TCP_UL_ch1_VHT20(self):
476        self._test_rvr()
477
478    @test_tracker_info(uuid='e912db87-dbfb-4e86-b91c-827e6c53e840')
479    def test_rvr_TCP_DL_ch6_VHT20(self):
480        self._test_rvr()
481
482    @test_tracker_info(uuid='ddafbe78-bd19-48fc-b653-69b23b1ab8dd')
483    def test_rvr_TCP_UL_ch6_VHT20(self):
484        self._test_rvr()
485
486    @test_tracker_info(uuid='6fcb7fd8-4438-4913-a1c8-ea35050c79dd')
487    def test_rvr_TCP_DL_ch11_VHT20(self):
488        self._test_rvr()
489
490    @test_tracker_info(uuid='a165884e-c928-46d9-b459-f550ceb0074f')
491    def test_rvr_TCP_UL_ch11_VHT20(self):
492        self._test_rvr()
493
494    @test_tracker_info(uuid='a48ee2b4-3fb9-41fd-b292-0051bfc3b0cc')
495    def test_rvr_TCP_DL_ch36_VHT20(self):
496        self._test_rvr()
497
498    @test_tracker_info(uuid='68f94e6b-b4ff-4839-904b-ec45cc661b89')
499    def test_rvr_TCP_UL_ch36_VHT20(self):
500        self._test_rvr()
501
502    @test_tracker_info(uuid='a8b00098-5c07-44bb-ae17-5d0489786c62')
503    def test_rvr_TCP_DL_ch36_VHT40(self):
504        self._test_rvr()
505
506    @test_tracker_info(uuid='ecfb4284-1794-4508-b35e-be56fa4c9035')
507    def test_rvr_TCP_UL_ch36_VHT40(self):
508        self._test_rvr()
509
510    @test_tracker_info(uuid='6190c1a6-08f2-4a27-a65f-7321801f2cd6')
511    def test_rvr_TCP_DL_ch36_VHT80(self):
512        self._test_rvr()
513
514    @test_tracker_info(uuid='ae12712d-0ac3-4317-827d-544acfa4910c')
515    def test_rvr_TCP_UL_ch36_VHT80(self):
516        self._test_rvr()
517
518    @test_tracker_info(uuid='c8f8d107-5176-484b-a0d9-7a63aef8677e')
519    def test_rvr_TCP_DL_ch40_VHT20(self):
520        self._test_rvr()
521
522    @test_tracker_info(uuid='6fa823c9-54bf-450d-b2c3-31a46fc73386')
523    def test_rvr_TCP_UL_ch40_VHT20(self):
524        self._test_rvr()
525
526    @test_tracker_info(uuid='aa6cd955-eaef-4552-87a4-c4a0df59e184')
527    def test_rvr_TCP_DL_ch44_VHT20(self):
528        self._test_rvr()
529
530    @test_tracker_info(uuid='14ad4b1c-7c8f-4650-be74-daf813021ad3')
531    def test_rvr_TCP_UL_ch44_VHT20(self):
532        self._test_rvr()
533
534    @test_tracker_info(uuid='a5fdb54c-60e2-4cc6-a9ec-1a17e7827823')
535    def test_rvr_TCP_DL_ch44_VHT40(self):
536        self._test_rvr()
537
538    @test_tracker_info(uuid='112113f1-7f50-4112-81b5-d9a4fdf153e7')
539    def test_rvr_TCP_UL_ch44_VHT40(self):
540        self._test_rvr()
541
542    @test_tracker_info(uuid='cda3886c-8776-4077-acfd-cfe128772e2f')
543    def test_rvr_TCP_DL_ch48_VHT20(self):
544        self._test_rvr()
545
546    @test_tracker_info(uuid='2e5ad031-6404-4e71-b3b3-8a3bb2c85d4f')
547    def test_rvr_TCP_UL_ch48_VHT20(self):
548        self._test_rvr()
549
550    @test_tracker_info(uuid='c2e199ce-d23f-4a24-b146-74e762085620')
551    def test_rvr_TCP_DL_ch52_VHT20(self):
552        self._test_rvr()
553
554    @test_tracker_info(uuid='5c5943e8-9d91-4270-a5ab-e7018807c64e')
555    def test_rvr_TCP_UL_ch52_VHT20(self):
556        self._test_rvr()
557
558    @test_tracker_info(uuid='b52afe89-182f-4bad-8879-cbf7001d28ef')
559    def test_rvr_TCP_DL_ch56_VHT20(self):
560        self._test_rvr()
561
562    @test_tracker_info(uuid='f8526241-3b96-463a-9082-a749a8650d5f')
563    def test_rvr_TCP_UL_ch56_VHT20(self):
564        self._test_rvr()
565
566    @test_tracker_info(uuid='c3042d7e-7468-4ab8-aec3-9b3088ba3e4c')
567    def test_rvr_TCP_DL_ch60_VHT20(self):
568        self._test_rvr()
569
570    @test_tracker_info(uuid='80426542-b035-4fb3-9010-e997f95d4964')
571    def test_rvr_TCP_UL_ch60_VHT20(self):
572        self._test_rvr()
573
574    @test_tracker_info(uuid='aa0e7117-390c-4265-adf2-0990f65f8b0b')
575    def test_rvr_TCP_DL_ch64_VHT20(self):
576        self._test_rvr()
577
578    @test_tracker_info(uuid='b2fdda85-256b-4368-8e8b-39274062264e')
579    def test_rvr_TCP_UL_ch64_VHT20(self):
580        self._test_rvr()
581
582    @test_tracker_info(uuid='48b6590f-1553-4170-83a5-40d3976e9e77')
583    def test_rvr_TCP_DL_ch100_VHT20(self):
584        self._test_rvr()
585
586    @test_tracker_info(uuid='2d0525fe-57ce-49d3-826d-4ebedd2ca6d6')
587    def test_rvr_TCP_UL_ch100_VHT20(self):
588        self._test_rvr()
589
590    @test_tracker_info(uuid='52da922d-6c2f-4afa-aca3-c19438ae3217')
591    def test_rvr_TCP_DL_ch100_VHT40(self):
592        self._test_rvr()
593
594    @test_tracker_info(uuid='2c7e7106-88c8-47ba-ac28-362475abec41')
595    def test_rvr_TCP_UL_ch100_VHT40(self):
596        self._test_rvr()
597
598    @test_tracker_info(uuid='fd4a7118-e9fe-4931-b32c-f69efd3e6493')
599    def test_rvr_TCP_DL_ch100_VHT80(self):
600        self._test_rvr()
601
602    @test_tracker_info(uuid='146502b2-9cab-4bbe-8a5c-7ec625edc2ef')
603    def test_rvr_TCP_UL_ch100_VHT80(self):
604        self._test_rvr()
605
606    @test_tracker_info(uuid='a5e185d6-b523-4016-bc8a-2a32cdc67ae0')
607    def test_rvr_TCP_DL_ch104_VHT20(self):
608        self._test_rvr()
609
610    @test_tracker_info(uuid='886aed91-0fdc-432d-b47e-ebfa85ac27ad')
611    def test_rvr_TCP_UL_ch104_VHT20(self):
612        self._test_rvr()
613
614    @test_tracker_info(uuid='fda3de6e-3183-401b-b98c-1b076da139e1')
615    def test_rvr_TCP_DL_ch108_VHT20(self):
616        self._test_rvr()
617
618    @test_tracker_info(uuid='29cc30f5-bbc8-4b64-9789-a56154907af5')
619    def test_rvr_TCP_UL_ch108_VHT20(self):
620        self._test_rvr()
621
622    @test_tracker_info(uuid='5c52ccac-8c38-46fa-a7b3-d714b6a814ad')
623    def test_rvr_TCP_DL_ch112_VHT20(self):
624        self._test_rvr()
625
626    @test_tracker_info(uuid='cc1c2a0b-71a3-4343-b7ff-489527c839d2')
627    def test_rvr_TCP_UL_ch112_VHT20(self):
628        self._test_rvr()
629
630    @test_tracker_info(uuid='11c6ccc3-e347-44ce-9a79-6c90e9dfd0a0')
631    def test_rvr_TCP_DL_ch116_VHT20(self):
632        self._test_rvr()
633
634    @test_tracker_info(uuid='29f0fce1-005d-4ad7-97d7-6b43cbdff01b')
635    def test_rvr_TCP_UL_ch116_VHT20(self):
636        self._test_rvr()
637
638    @test_tracker_info(uuid='112302b1-8261-479a-b397-916b08fbbdd2')
639    def test_rvr_TCP_DL_ch132_VHT20(self):
640        self._test_rvr()
641
642    @test_tracker_info(uuid='3bb0efb8-ddfc-4a0b-b7cf-6d6af1dbb9f4')
643    def test_rvr_TCP_UL_ch132_VHT20(self):
644        self._test_rvr()
645
646    @test_tracker_info(uuid='11a4638f-d872-4730-82eb-71d9c64e0e16')
647    def test_rvr_TCP_DL_ch136_VHT20(self):
648        self._test_rvr()
649
650    @test_tracker_info(uuid='4d797c24-3bbe-43a6-ac9e-291db1aa732a')
651    def test_rvr_TCP_UL_ch136_VHT20(self):
652        self._test_rvr()
653
654    @test_tracker_info(uuid='5d433b44-0395-43cb-b85a-be138390b18b')
655    def test_rvr_TCP_DL_ch140_VHT20(self):
656        self._test_rvr()
657
658    @test_tracker_info(uuid='47061772-21b1-4330-bd4f-daec21afa0c8')
659    def test_rvr_TCP_UL_ch140_VHT20(self):
660        self._test_rvr()
661
662    @test_tracker_info(uuid='24aa1e7a-3978-4803-877f-3ac5812ab0ae')
663    def test_rvr_TCP_DL_ch149_VHT20(self):
664        self._test_rvr()
665
666    @test_tracker_info(uuid='59f0443f-822d-4347-9c52-310f0b812500')
667    def test_rvr_TCP_UL_ch149_VHT20(self):
668        self._test_rvr()
669
670    @test_tracker_info(uuid='3b1524b3-af15-41f1-8fca-9ee9b687d59a')
671    def test_rvr_TCP_DL_ch149_VHT40(self):
672        self._test_rvr()
673
674    @test_tracker_info(uuid='36670787-3bfb-4e8b-8881-e88eb608ed46')
675    def test_rvr_TCP_UL_ch149_VHT40(self):
676        self._test_rvr()
677
678    @test_tracker_info(uuid='8350cddd-7c62-4fad-bdae-a8267d321aa3')
679    def test_rvr_TCP_DL_ch149_VHT80(self):
680        self._test_rvr()
681
682    @test_tracker_info(uuid='7432fccb-526e-44d4-b0f4-2c343ca53188')
683    def test_rvr_TCP_UL_ch149_VHT80(self):
684        self._test_rvr()
685
686    @test_tracker_info(uuid='037eec49-2bae-49e3-949e-5af2885dc84b')
687    def test_rvr_TCP_DL_ch153_VHT20(self):
688        self._test_rvr()
689
690    @test_tracker_info(uuid='04d5d873-7d5a-4590-bff3-093edeb92380')
691    def test_rvr_TCP_UL_ch153_VHT20(self):
692        self._test_rvr()
693
694    @test_tracker_info(uuid='4ff83f6e-b130-4a88-8ced-04a09c6af666')
695    def test_rvr_TCP_DL_ch157_VHT20(self):
696        self._test_rvr()
697
698    @test_tracker_info(uuid='c3436402-977e-40a5-a7eb-e2c886379d43')
699    def test_rvr_TCP_UL_ch157_VHT20(self):
700        self._test_rvr()
701
702    @test_tracker_info(uuid='797a218b-1a8e-4233-835b-61b3f057f480')
703    def test_rvr_TCP_DL_ch157_VHT40(self):
704        self._test_rvr()
705
706    @test_tracker_info(uuid='38d3e825-6e2c-4931-b0fd-aa19c5d1ef40')
707    def test_rvr_TCP_UL_ch157_VHT40(self):
708        self._test_rvr()
709
710    @test_tracker_info(uuid='993e98c5-0647-4ed6-b62e-ab386ada37af')
711    def test_rvr_TCP_DL_ch161_VHT20(self):
712        self._test_rvr()
713
714    @test_tracker_info(uuid='3bf9c844-749a-47d8-ac46-89249bd92c4a')
715    def test_rvr_TCP_UL_ch161_VHT20(self):
716        self._test_rvr()
717
718    @test_tracker_info(uuid='05614f92-38fa-4289-bcff-d4b4a2a2ad5b')
719    def test_rvr_UDP_DL_ch6_VHT20(self):
720        self._test_rvr()
721
722    @test_tracker_info(uuid='577632e9-fb2f-4a2b-b3c3-affee8264008')
723    def test_rvr_UDP_UL_ch6_VHT20(self):
724        self._test_rvr()
725
726    @test_tracker_info(uuid='6f3fcc28-5f0c-49e6-8810-69c5873ecafa')
727    def test_rvr_UDP_DL_ch36_VHT20(self):
728        self._test_rvr()
729
730    @test_tracker_info(uuid='8e518aaa-e61f-4c1d-b12f-1bbd550ec3e5')
731    def test_rvr_UDP_UL_ch36_VHT20(self):
732        self._test_rvr()
733
734    @test_tracker_info(uuid='fd68ff32-c789-4a86-9924-2f5aeb3c9651')
735    def test_rvr_UDP_DL_ch149_VHT20(self):
736        self._test_rvr()
737
738    @test_tracker_info(uuid='29d03492-fc0b-42d0-aa15-c0c838ba50c1')
739    def test_rvr_UDP_UL_ch149_VHT20(self):
740        self._test_rvr()
741
742    @test_tracker_info(uuid='044c414c-ac5e-4e28-9b56-a602e0cc9724')
743    def test_rvr_UDP_DL_ch36_VHT40(self):
744        self._test_rvr()
745
746    @test_tracker_info(uuid='9cd16689-5053-4ffa-813c-d901384a105c')
747    def test_rvr_UDP_UL_ch36_VHT40(self):
748        self._test_rvr()
749
750    @test_tracker_info(uuid='4e4b1e73-30ce-4005-9c34-8c0280bdb293')
751    def test_rvr_UDP_DL_ch36_VHT80(self):
752        self._test_rvr()
753
754    @test_tracker_info(uuid='780166a1-1847-45c2-b509-71612c82309d')
755    def test_rvr_UDP_UL_ch36_VHT80(self):
756        self._test_rvr()
757
758    @test_tracker_info(uuid='05abdb89-9744-479e-8443-cb8b9427f5e3')
759    def test_rvr_UDP_DL_ch149_VHT40(self):
760        self._test_rvr()
761
762    @test_tracker_info(uuid='a321590a-4cbc-4044-9c2b-24e90f444213')
763    def test_rvr_UDP_UL_ch149_VHT40(self):
764        self._test_rvr()
765
766    @test_tracker_info(uuid='041fd613-24d9-4606-bca3-0ae0d8436b5e')
767    def test_rvr_UDP_DL_ch149_VHT80(self):
768        self._test_rvr()
769
770    @test_tracker_info(uuid='69aab23d-1408-4cdd-9f57-2520a1e9cea8')
771    def test_rvr_UDP_UL_ch149_VHT80(self):
772        self._test_rvr()
773
774
775# Classes defining test suites
776class WifiRvr_2GHz_Test(WifiRvrTest):
777    def __init__(self, controllers):
778        super().__init__(controllers)
779        self.tests = ("test_rvr_TCP_DL_ch1_VHT20", "test_rvr_TCP_UL_ch1_VHT20",
780                      "test_rvr_TCP_DL_ch6_VHT20", "test_rvr_TCP_UL_ch6_VHT20",
781                      "test_rvr_TCP_DL_ch11_VHT20",
782                      "test_rvr_TCP_UL_ch11_VHT20")
783
784
785class WifiRvr_UNII1_Test(WifiRvrTest):
786    def __init__(self, controllers):
787        super().__init__(controllers)
788        self.tests = (
789            "test_rvr_TCP_DL_ch36_VHT20", "test_rvr_TCP_UL_ch36_VHT20",
790            "test_rvr_TCP_DL_ch36_VHT40", "test_rvr_TCP_UL_ch36_VHT40",
791            "test_rvr_TCP_DL_ch36_VHT80", "test_rvr_TCP_UL_ch36_VHT80",
792            "test_rvr_TCP_DL_ch40_VHT20", "test_rvr_TCP_UL_ch40_VHT20",
793            "test_rvr_TCP_DL_ch44_VHT20", "test_rvr_TCP_UL_ch44_VHT20",
794            "test_rvr_TCP_DL_ch44_VHT40", "test_rvr_TCP_UL_ch44_VHT40",
795            "test_rvr_TCP_DL_ch48_VHT20", "test_rvr_TCP_UL_ch48_VHT20")
796
797
798class WifiRvr_UNII3_Test(WifiRvrTest):
799    def __init__(self, controllers):
800        super().__init__(controllers)
801        self.tests = (
802            "test_rvr_TCP_DL_ch149_VHT20", "test_rvr_TCP_UL_ch149_VHT20",
803            "test_rvr_TCP_DL_ch149_VHT40", "test_rvr_TCP_UL_ch149_VHT40",
804            "test_rvr_TCP_DL_ch149_VHT80", "test_rvr_TCP_UL_ch149_VHT80",
805            "test_rvr_TCP_DL_ch153_VHT20", "test_rvr_TCP_UL_ch153_VHT20",
806            "test_rvr_TCP_DL_ch157_VHT20", "test_rvr_TCP_UL_ch157_VHT20",
807            "test_rvr_TCP_DL_ch157_VHT40", "test_rvr_TCP_UL_ch157_VHT40",
808            "test_rvr_TCP_DL_ch161_VHT20", "test_rvr_TCP_UL_ch161_VHT20")
809
810
811class WifiRvr_SampleDFS_Test(WifiRvrTest):
812    def __init__(self, controllers):
813        super().__init__(controllers)
814        self.tests = (
815            "test_rvr_TCP_DL_ch64_VHT20", "test_rvr_TCP_UL_ch64_VHT20",
816            "test_rvr_TCP_DL_ch100_VHT20", "test_rvr_TCP_UL_ch100_VHT20",
817            "test_rvr_TCP_DL_ch100_VHT40", "test_rvr_TCP_UL_ch100_VHT40",
818            "test_rvr_TCP_DL_ch100_VHT80", "test_rvr_TCP_UL_ch100_VHT80",
819            "test_rvr_TCP_DL_ch116_VHT20", "test_rvr_TCP_UL_ch116_VHT20",
820            "test_rvr_TCP_DL_ch132_VHT20", "test_rvr_TCP_UL_ch132_VHT20",
821            "test_rvr_TCP_DL_ch140_VHT20", "test_rvr_TCP_UL_ch140_VHT20")
822
823
824class WifiRvr_SampleUDP_Test(WifiRvrTest):
825    def __init__(self, controllers):
826        super().__init__(controllers)
827        self.tests = (
828            "test_rvr_UDP_DL_ch6_VHT20", "test_rvr_UDP_UL_ch6_VHT20",
829            "test_rvr_UDP_DL_ch36_VHT20", "test_rvr_UDP_UL_ch36_VHT20",
830            "test_rvr_UDP_DL_ch36_VHT40", "test_rvr_UDP_UL_ch36_VHT40",
831            "test_rvr_UDP_DL_ch36_VHT80", "test_rvr_UDP_UL_ch36_VHT80",
832            "test_rvr_UDP_DL_ch149_VHT20", "test_rvr_UDP_UL_ch149_VHT20",
833            "test_rvr_UDP_DL_ch149_VHT40", "test_rvr_UDP_UL_ch149_VHT40",
834            "test_rvr_UDP_DL_ch149_VHT80", "test_rvr_UDP_UL_ch149_VHT80")
835
836
837class WifiRvr_TCP_All_Test(WifiRvrTest):
838    def __init__(self, controllers):
839        super().__init__(controllers)
840        self.tests = (
841            "test_rvr_TCP_DL_ch1_VHT20", "test_rvr_TCP_UL_ch1_VHT20",
842            "test_rvr_TCP_DL_ch6_VHT20", "test_rvr_TCP_UL_ch6_VHT20",
843            "test_rvr_TCP_DL_ch11_VHT20", "test_rvr_TCP_UL_ch11_VHT20",
844            "test_rvr_TCP_DL_ch36_VHT20", "test_rvr_TCP_UL_ch36_VHT20",
845            "test_rvr_TCP_DL_ch36_VHT40", "test_rvr_TCP_UL_ch36_VHT40",
846            "test_rvr_TCP_DL_ch36_VHT80", "test_rvr_TCP_UL_ch36_VHT80",
847            "test_rvr_TCP_DL_ch40_VHT20", "test_rvr_TCP_UL_ch40_VHT20",
848            "test_rvr_TCP_DL_ch44_VHT20", "test_rvr_TCP_UL_ch44_VHT20",
849            "test_rvr_TCP_DL_ch44_VHT40", "test_rvr_TCP_UL_ch44_VHT40",
850            "test_rvr_TCP_DL_ch48_VHT20", "test_rvr_TCP_UL_ch48_VHT20",
851            "test_rvr_TCP_DL_ch149_VHT20", "test_rvr_TCP_UL_ch149_VHT20",
852            "test_rvr_TCP_DL_ch149_VHT40", "test_rvr_TCP_UL_ch149_VHT40",
853            "test_rvr_TCP_DL_ch149_VHT80", "test_rvr_TCP_UL_ch149_VHT80",
854            "test_rvr_TCP_DL_ch153_VHT20", "test_rvr_TCP_UL_ch153_VHT20",
855            "test_rvr_TCP_DL_ch157_VHT20", "test_rvr_TCP_UL_ch157_VHT20",
856            "test_rvr_TCP_DL_ch157_VHT40", "test_rvr_TCP_UL_ch157_VHT40",
857            "test_rvr_TCP_DL_ch161_VHT20", "test_rvr_TCP_UL_ch161_VHT20")
858
859
860class WifiRvr_TCP_Downlink_Test(WifiRvrTest):
861    def __init__(self, controllers):
862        super().__init__(controllers)
863        self.tests = (
864            "test_rvr_TCP_DL_ch1_VHT20", "test_rvr_TCP_DL_ch6_VHT20",
865            "test_rvr_TCP_DL_ch11_VHT20", "test_rvr_TCP_DL_ch36_VHT20",
866            "test_rvr_TCP_DL_ch36_VHT40", "test_rvr_TCP_DL_ch36_VHT80",
867            "test_rvr_TCP_DL_ch40_VHT20", "test_rvr_TCP_DL_ch44_VHT20",
868            "test_rvr_TCP_DL_ch44_VHT40", "test_rvr_TCP_DL_ch48_VHT20",
869            "test_rvr_TCP_DL_ch149_VHT20", "test_rvr_TCP_DL_ch149_VHT40",
870            "test_rvr_TCP_DL_ch149_VHT80", "test_rvr_TCP_DL_ch153_VHT20",
871            "test_rvr_TCP_DL_ch157_VHT20", "test_rvr_TCP_DL_ch157_VHT40",
872            "test_rvr_TCP_DL_ch161_VHT20")
873
874
875class WifiRvr_TCP_Uplink_Test(WifiRvrTest):
876    def __init__(self, controllers):
877        super().__init__(controllers)
878        self.tests = (
879            "test_rvr_TCP_UL_ch1_VHT20", "test_rvr_TCP_UL_ch6_VHT20",
880            "test_rvr_TCP_UL_ch11_VHT20", "test_rvr_TCP_UL_ch36_VHT20",
881            "test_rvr_TCP_UL_ch36_VHT40", "test_rvr_TCP_UL_ch36_VHT80",
882            "test_rvr_TCP_UL_ch40_VHT20", "test_rvr_TCP_UL_ch44_VHT20",
883            "test_rvr_TCP_UL_ch44_VHT40", "test_rvr_TCP_UL_ch48_VHT20",
884            "test_rvr_TCP_UL_ch149_VHT20", "test_rvr_TCP_UL_ch149_VHT40",
885            "test_rvr_TCP_UL_ch149_VHT80", "test_rvr_TCP_UL_ch153_VHT20",
886            "test_rvr_TCP_UL_ch157_VHT20", "test_rvr_TCP_UL_ch157_VHT40",
887            "test_rvr_TCP_UL_ch161_VHT20")
888