1#!/usr/bin/env python3
2#
3# Copyright (C) 2018 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may not
6# use this file except in compliance with the License. You may obtain a copy of
7# 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, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations under
15# the License.
16"""
17Script for testing WiFi connection and disconnection in a loop
18
19"""
20from acts.base_test import BaseTestClass
21
22import os
23import uuid
24import time
25
26from acts import signals
27from acts.controllers.ap_lib import hostapd_constants
28from acts.controllers.ap_lib import hostapd_security
29from acts.test_utils.abstract_devices.utils_lib.wlan_utils import setup_ap
30from acts.test_utils.abstract_devices.utils_lib.wlan_utils import associate
31from acts.test_utils.abstract_devices.utils_lib.wlan_utils import disconnect
32from acts.test_utils.abstract_devices.wlan_device import create_wlan_device
33from acts.test_utils.abstract_devices.wlan_device_lib.AbstractDeviceWlanDeviceBaseTest import AbstractDeviceWlanDeviceBaseTest
34from acts.test_utils.fuchsia import utils
35from acts.test_utils.tel.tel_test_utils import setup_droid_properties
36from acts.utils import rand_ascii_str
37
38
39class ConnectionStressTest(AbstractDeviceWlanDeviceBaseTest):
40    # Default number of test iterations here.
41    # Override using parameter in config file.
42    # Eg: "connection_stress_test_iterations": "50"
43    num_of_iterations = 10
44    channel_2G = hostapd_constants.AP_DEFAULT_CHANNEL_2G
45    channel_5G = hostapd_constants.AP_DEFAULT_CHANNEL_5G
46
47    def setup_class(self):
48        super().setup_class()
49        self.ssid = rand_ascii_str(10)
50        self.fd = self.fuchsia_devices[0]
51        self.dut = create_wlan_device(self.fd)
52        self.ap = self.access_points[0]
53        self.num_of_iterations = int(
54            self.user_params.get("connection_stress_test_iterations",
55                                 self.num_of_iterations))
56        self.log.info('iterations: %d' % self.num_of_iterations)
57
58    def teardown_test(self):
59        self.dut.reset_wifi()
60        self.ap.stop_all_aps()
61
62    def on_fail(self, test_name, begin_time):
63        super().on_fail(test_name, begin_time)
64        self.access_point.stop_all_aps()
65
66    def start_ap(self, profile, channel, security=None):
67        """Starts an Access Point
68
69        Args:
70            profile: Profile name such as 'whirlwind'
71            channel: Channel to operate on
72        """
73        self.log.info('Profile: %s, Channel: %d' % (profile, channel))
74        setup_ap(access_point=self.ap,
75                 profile_name=profile,
76                 channel=channel,
77                 ssid=self.ssid,
78                 security=security)
79
80    def connect_disconnect(self,
81                           ap_config,
82                           ssid=None,
83                           password=None,
84                           negative_test=False):
85        """Helper to start an AP, connect DUT to it and disconnect
86
87        Args:
88            ap_config: Dictionary contaning profile name and channel
89            ssid: ssid to connect to
90            password: password for the ssid to connect to
91        """
92        # Start AP
93        self.start_ap(ap_config['profile'], ap_config['channel'],
94                      ap_config['security'])
95
96        failed = False
97        # Connect and Disconnect several times
98        for x in range(0, self.num_of_iterations):
99            if not ssid:
100                ssid = self.ssid
101            if negative_test:
102                if not associate(self.dut, ssid=ssid, password=password):
103                    self.log.info(
104                        'Attempt %d. Did not associate as expected.' % x)
105                else:
106                    self.log.error('Attempt %d. Negative test successfully '
107                                   'associated. Fail.' % x)
108                    failed = True
109            else:
110                # Connect
111                if associate(self.dut, ssid=ssid, password=password):
112                    self.log.info('Attempt %d. Successfully associated' % x)
113                else:
114                    self.log.error('Attempt %d. Failed to associate.' % x)
115                    failed = True
116                # Disconnect
117                disconnect(self.dut)
118
119            # Wait a second before trying again
120            time.sleep(1)
121
122        # Stop AP
123        self.ap.stop_all_aps()
124        if failed:
125            raise signals.TestFailure(
126                'One or more association attempt failed.')
127
128    def test_whirlwind_2g(self):
129        self.connect_disconnect({
130            'profile': 'whirlwind',
131            'channel': self.channel_2G,
132            'security': None
133        })
134
135    def test_whirlwind_5g(self):
136        self.connect_disconnect({
137            'profile': 'whirlwind',
138            'channel': self.channel_5G,
139            'security': None
140        })
141
142    def test_whirlwind_11ab_2g(self):
143        self.connect_disconnect({
144            'profile': 'whirlwind_11ab_legacy',
145            'channel': self.channel_2G,
146            'security': None
147        })
148
149    def test_whirlwind_11ab_5g(self):
150        self.connect_disconnect({
151            'profile': 'whirlwind_11ab_legacy',
152            'channel': self.channel_5G,
153            'security': None
154        })
155
156    def test_whirlwind_11ag_2g(self):
157        self.connect_disconnect({
158            'profile': 'whirlwind_11ag_legacy',
159            'channel': self.channel_2G,
160            'security': None
161        })
162
163    def test_whirlwind_11ag_5g(self):
164        self.connect_disconnect({
165            'profile': 'whirlwind_11ag_legacy',
166            'channel': self.channel_5G,
167            'security': None
168        })
169
170    def test_wrong_ssid_whirlwind_2g(self):
171        self.connect_disconnect(
172            {
173                'profile': 'whirlwind',
174                'channel': self.channel_2G,
175                'security': None
176            },
177            ssid=rand_ascii_str(20),
178            negative_test=True)
179
180    def test_wrong_ssid_whirlwind_5g(self):
181        self.connect_disconnect(
182            {
183                'profile': 'whirlwind',
184                'channel': self.channel_5G,
185                'security': None
186            },
187            ssid=rand_ascii_str(20),
188            negative_test=True)
189
190    def test_wrong_password_whirlwind_2g(self):
191        self.connect_disconnect(
192            {
193                'profile':
194                'whirlwind',
195                'channel':
196                self.channel_2G,
197                'security':
198                hostapd_security.Security(security_mode='wpa2',
199                                          password=rand_ascii_str(10))
200            },
201            password=rand_ascii_str(20),
202            negative_test=True)
203
204    def test_wrong_password_whirlwind_5g(self):
205        self.connect_disconnect(
206            {
207                'profile':
208                'whirlwind',
209                'channel':
210                self.channel_5G,
211                'security':
212                hostapd_security.Security(security_mode='wpa2',
213                                          password=rand_ascii_str(10))
214            },
215            password=rand_ascii_str(20),
216            negative_test=True)
217