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