• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3.4
2#
3#   Copyright 2019 - 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 itertools
19import json
20import os
21from acts import base_test
22from acts import context
23from acts.metrics.loggers.blackbox import BlackboxMetricLogger
24from acts.test_utils.wifi import ota_chamber
25from acts.test_utils.wifi import wifi_performance_test_utils as wputils
26from WifiRvrTest import WifiRvrTest
27from WifiPingTest import WifiPingTest
28
29
30class WifiOtaRvrTest(WifiRvrTest):
31    """Class to test over-the-air RvR
32
33    This class implements measures WiFi RvR tests in an OTA chamber. It enables
34    setting turntable orientation and other chamber parameters to study
35    performance in varying channel conditions
36    """
37
38    def __init__(self, controllers):
39        base_test.BaseTestClass.__init__(self, controllers)
40        self.failure_count_metric = BlackboxMetricLogger.for_test_case(
41            metric_name='failure_count')
42
43    def setup_class(self):
44        WifiRvrTest.setup_class(self)
45        req_params = ['OTAChamber']
46        self.unpack_userparams(req_params)
47        self.ota_chambers = ota_chamber.create(self.OTAChamber)
48        self.ota_chamber = self.ota_chambers[0]
49
50    def teardown_class(self):
51        WifiRvrTest.teardown_class(self)
52        self.ota_chamber.set_orientation(0)
53
54    def setup_rvr_test(self, testcase_params):
55        """Function that gets devices ready for the test.
56
57        Args:
58            testcase_params: dict containing test-specific parameters
59        """
60        # Set turntable orientation
61        self.ota_chamber.set_orientation(testcase_params['orientation'])
62        # Continue test setup
63        WifiRvrTest.setup_rvr_test(self, testcase_params)
64
65    def parse_test_params(self, test_name):
66        """Function that generates test params based on the test name."""
67        # Call parent parsing function
68        testcase_params = WifiRvrTest.parse_test_params(self, test_name)
69        # Add orientation information
70        test_name_params = test_name.split('_')
71        testcase_params['orientation'] = int(test_name_params[6][0:-3])
72        return testcase_params
73
74    def generate_test_cases(self, channels, modes, angles, traffic_types,
75                            directions):
76        test_cases = []
77        testcase_wrapper = self._test_rvr
78        allowed_configs = {
79            'VHT20': [
80                1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 149, 153,
81                157, 161
82            ],
83            'VHT40': [36, 44, 149, 157],
84            'VHT80': [36, 149]
85        }
86        for channel, mode, angle, traffic_type, direction in itertools.product(
87                channels, modes, angles, traffic_types, directions):
88            if channel not in allowed_configs[mode]:
89                continue
90            testcase_name = 'test_rvr_{}_{}_ch{}_{}_{}deg'.format(
91                traffic_type, direction, channel, mode, angle)
92            setattr(self, testcase_name, testcase_wrapper)
93            test_cases.append(testcase_name)
94        return test_cases
95
96
97class WifiOtaRvr_StandardOrientation_Test(WifiOtaRvrTest):
98    def __init__(self, controllers):
99        WifiOtaRvrTest.__init__(self, controllers)
100        self.tests = self.generate_test_cases(
101            [1, 6, 11, 36, 40, 44, 48, 149, 153, 157, 161],
102            ['VHT20', 'VHT40', 'VHT80'], list(range(0, 360,
103                                                    45)), ['TCP'], ['DL'])
104
105
106class WifiOtaRvr_SampleChannel_Test(WifiOtaRvrTest):
107    def __init__(self, controllers):
108        WifiOtaRvrTest.__init__(self, controllers)
109        self.tests = self.generate_test_cases([6, 36, 149], ['VHT20', 'VHT80'],
110                                              list(range(0, 360, 45)), ['TCP'],
111                                              ['DL'])
112
113
114class WifiOtaRvr_SingleOrientation_Test(WifiOtaRvrTest):
115    def __init__(self, controllers):
116        WifiOtaRvrTest.__init__(self, controllers)
117        self.tests = self.generate_test_cases(
118            [6, 36, 40, 44, 48, 149, 153, 157, 161],
119            ['VHT20', 'VHT40', 'VHT80'], [0], ['TCP'], ['DL', 'UL'])
120
121
122# Ping Tests
123class WifiOtaPingTest(WifiPingTest):
124    """Class to test over-the-air ping
125
126    This class tests WiFi ping performance in an OTA chamber. It enables
127    setting turntable orientation and other chamber parameters to study
128    performance in varying channel conditions
129    """
130
131    def __init__(self, controllers):
132        base_test.BaseTestClass.__init__(self, controllers)
133        self.ping_range_metric = BlackboxMetricLogger.for_test_case(
134            metric_name='ping_range')
135        self.ping_rtt_metric = BlackboxMetricLogger.for_test_case(
136            metric_name='ping_rtt')
137
138    def setup_class(self):
139        WifiPingTest.setup_class(self)
140        req_params = ['OTAChamber']
141        self.unpack_userparams(req_params)
142        self.ota_chambers = ota_chamber.create(self.OTAChamber)
143        self.ota_chamber = self.ota_chambers[0]
144
145    def teardown_class(self):
146        self.process_testclass_results()
147        self.ota_chamber.set_orientation(0)
148
149    def process_testclass_results(self):
150        """Saves all test results to enable comparison."""
151        WifiPingTest.process_testclass_results(self)
152
153        range_vs_angle = collections.OrderedDict()
154        for test in self.testclass_results:
155            curr_params = self.parse_test_params(test['test_name'])
156            curr_config = curr_params['channel']
157            if curr_config in range_vs_angle:
158                range_vs_angle[curr_config]['orientation'].append(
159                    curr_params['orientation'])
160                range_vs_angle[curr_config]['range'].append(test['range'])
161            else:
162                range_vs_angle[curr_config] = {
163                    'orientation': [curr_params['orientation']],
164                    'range': [test['range']]
165                }
166        figure = wputils.BokehFigure(
167            title='Range vs. Orientation',
168            x_label='Angle (deg)',
169            primary_y='Range (dB)',
170        )
171        for config, config_data in range_vs_angle.items():
172            figure.add_line(config_data['orientation'], config_data['range'],
173                            'Channel {}'.format(config))
174        current_context = context.get_current_context().get_full_output_path()
175        plot_file_path = os.path.join(current_context, 'results.html')
176        figure.generate_figure(plot_file_path)
177
178        # Save results
179        results_file_path = os.path.join(current_context,
180                                         'testclass_summary.json')
181        with open(results_file_path, 'w') as results_file:
182            json.dump(range_vs_angle, results_file, indent=4)
183
184    def setup_ping_test(self, testcase_params):
185        """Function that gets devices ready for the test.
186
187        Args:
188            testcase_params: dict containing test-specific parameters
189        """
190        # Configure AP
191        self.setup_ap(testcase_params)
192        # Set attenuator to 0 dB
193        for attenuator in self.attenuators:
194            attenuator.set_atten(0, strict=False)
195        # Setup turntable
196        self.ota_chamber.set_orientation(testcase_params['orientation'])
197        # Reset, configure, and connect DUT
198        self.setup_dut(testcase_params)
199
200    def parse_test_params(self, test_name):
201        """Function that generates test params based on the test name."""
202        # Call parent parsing function
203        testcase_params = WifiPingTest.parse_test_params(self, test_name)
204        # Add orientation information
205        test_name_params = test_name.split('_')
206        testcase_params['orientation'] = int(test_name_params[5][0:-3])
207        return testcase_params
208
209    def generate_test_cases(self, channels, modes, angles):
210        test_cases = []
211        testcase_wrapper = self._test_ping_range
212        allowed_configs = {
213            'VHT20': [
214                1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 149, 153,
215                157, 161
216            ],
217            'VHT40': [36, 44, 149, 157],
218            'VHT80': [36, 149]
219        }
220        for channel, mode, angle in itertools.product(channels, modes, angles):
221            if channel not in allowed_configs[mode]:
222                continue
223            testcase_name = 'test_ping_range_ch{}_{}_{}deg'.format(
224                channel, mode, angle)
225            setattr(self, testcase_name, testcase_wrapper)
226            test_cases.append(testcase_name)
227        return test_cases
228
229
230class WifiOtaPing_TenDegree_Test(WifiOtaPingTest):
231    def __init__(self, controllers):
232        WifiOtaPingTest.__init__(self, controllers)
233        self.tests = self.generate_test_cases(
234            [1, 6, 11, 36, 40, 44, 48, 149, 153, 157, 161], ['VHT20'],
235            list(range(0, 360, 10)))
236
237
238class WifiOtaPing_45Degree_Test(WifiOtaPingTest):
239    def __init__(self, controllers):
240        WifiOtaPingTest.__init__(self, controllers)
241        self.tests = self.generate_test_cases(
242            [1, 6, 11, 36, 40, 44, 48, 149, 153, 157, 161], ['VHT20'],
243            list(range(0, 360, 45)))
244