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.fuchsia import utils
34from acts.test_utils.tel.tel_test_utils import setup_droid_properties
35from acts.utils import rand_ascii_str
36
37
38
39class ConnectionStressTest(BaseTestClass):
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 start_ap(self, profile, channel, security=None):
63        """Starts an Access Point
64
65        Args:
66            profile: Profile name such as 'whirlwind'
67            channel: Channel to operate on
68        """
69        self.log.info('Profile: %s, Channel: %d' % (profile, channel))
70        setup_ap(
71            access_point=self.ap,
72            profile_name=profile,
73            channel=channel,
74            ssid=self.ssid,
75            security=security)
76
77    def connect_disconnect(self,
78                           ap_config,
79                           ssid=None,
80                           password=None,
81                           negative_test=False):
82        """Helper to start an AP, connect DUT to it and disconnect
83
84        Args:
85            ap_config: Dictionary contaning profile name and channel
86            ssid: ssid to connect to
87            password: password for the ssid to connect to
88        """
89        # Start AP
90        self.start_ap(ap_config['profile'],
91                      ap_config['channel'],
92                      ap_config['security'])
93
94        failed = False
95        # Connect and Disconnect several times
96        for x in range(0, self.num_of_iterations):
97            if not ssid:
98                ssid = self.ssid
99            if negative_test:
100                if not associate(self.dut, ssid=ssid, password=password):
101                    self.log.info('Attempt %d. Did not associate as expected.'
102                                  % x)
103                else:
104                    self.log.error('Attempt %d. Negative test successfully '
105                                   'associated. Fail.' % x)
106                    failed = True
107            else:
108                # Connect
109                if associate(self.dut, ssid=ssid, password=password):
110                    self.log.info('Attempt %d. Successfully associated' % x)
111                else:
112                    self.log.error('Attempt %d. Failed to associate.' % x)
113                    failed = True
114                # Disconnect
115                disconnect(self.dut)
116
117            # Wait a second before trying again
118            time.sleep(1)
119
120        # Stop AP
121        self.ap.stop_all_aps()
122        if failed:
123            raise signals.TestFailure('One or more association attempt failed.')
124
125    def test_whirlwind_2g(self):
126        self.connect_disconnect({
127            'profile': 'whirlwind',
128            'channel': self.channel_2G,
129            'security': None
130        })
131
132    def test_whirlwind_5g(self):
133        self.connect_disconnect({
134            'profile': 'whirlwind',
135            'channel': self.channel_5G,
136            'security': None
137        })
138
139    def test_whirlwind_11ab_2g(self):
140        self.connect_disconnect({
141            'profile': 'whirlwind_11ab_legacy',
142            'channel': self.channel_2G,
143            'security': None
144        })
145
146    def test_whirlwind_11ab_5g(self):
147        self.connect_disconnect({
148            'profile': 'whirlwind_11ab_legacy',
149            'channel': self.channel_5G,
150            'security': None
151        })
152
153    def test_whirlwind_11ag_2g(self):
154        self.connect_disconnect({
155            'profile': 'whirlwind_11ag_legacy',
156            'channel': self.channel_2G,
157            'security': None
158        })
159
160    def test_whirlwind_11ag_5g(self):
161        self.connect_disconnect({
162            'profile': 'whirlwind_11ag_legacy',
163            'channel': self.channel_5G,
164            'security': None
165        })
166
167    def test_wrong_ssid_whirlwind_2g(self):
168        self.connect_disconnect(
169            {
170                'profile': 'whirlwind',
171                'channel': self.channel_2G,
172                'security': None
173            },
174            ssid=rand_ascii_str(20),
175            negative_test=True
176        )
177
178    def test_wrong_ssid_whirlwind_5g(self):
179        self.connect_disconnect(
180            {
181                'profile': 'whirlwind',
182                'channel': self.channel_5G,
183                'security': None
184            },
185            ssid=rand_ascii_str(20),
186            negative_test=True
187        )
188
189    def test_wrong_password_whirlwind_2g(self):
190        self.connect_disconnect(
191            {
192                'profile': 'whirlwind',
193                'channel': self.channel_2G,
194                'security': hostapd_security.Security(
195                    security_mode='wpa2',
196                    password=rand_ascii_str(10))
197            },
198            password=rand_ascii_str(20),
199            negative_test=True
200        )
201
202    def test_wrong_password_whirlwind_5g(self):
203        self.connect_disconnect(
204            {
205                'profile': 'whirlwind',
206                'channel': self.channel_5G,
207                'security': hostapd_security.Security(
208                    security_mode='wpa2',
209                    password=rand_ascii_str(10))
210            },
211            password=rand_ascii_str(20),
212            negative_test=True
213        )