1# Copyright (c) 2012 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Unit test for ap_configurator."""
6
7import os
8import sys
9import unittest
10
11# Define autotest_lib MAGIC!
12sys.path.append(os.path.join(
13                os.path.dirname(os.path.abspath(__file__)), '..', '..', '..'))
14from utils import common
15
16from autotest_lib.server.cros import host_lock_manager
17import ap_batch_locker
18import ap_spec
19
20
21class ConfiguratorTest(unittest.TestCase):
22    """This test needs to be run against the UI interface of a real AP.
23
24    The purpose of this test is to act as a basic acceptance test when
25    developing a new AP configurator class.  Use this to make sure all core
26    functionality is implemented.
27
28    This test does not verify that everything works for ALL APs. It only
29    tests against the AP specified below in AP_SPEC.
30
31    Launch this unit test from outside chroot:
32      $ cd ~/chromeos/src/third_party/autotest/files
33      $ python utils/unittest_suite.py \
34        server.cros.ap_configurators.ap_configurator_test --debug
35
36    To run a single test, from outside chroot, e.g.
37      $ cd ~/chromeos/src/third_party/autotest/files/\
38           server/cros/ap_configurators
39      $ python -m unittest ap_configurator_test.ConfiguratorTest.test_ssid
40    """
41
42    # Enter the hostname of the AP to test against
43    AP_SPEC = ap_spec.APSpec(hostnames=['chromeos3-row4-rack1-host9'])
44
45    # Do not actually power up the AP, assume it is on.
46    OVERRIDE_POWER = True
47
48    @classmethod
49    def setUpClass(self):
50        lock_manager = host_lock_manager.HostLockManager()
51        self.batch_locker = ap_batch_locker.ApBatchLocker(lock_manager,
52                            self.AP_SPEC, hostname_matching_only=True)
53        ap_batch = self.batch_locker.get_ap_batch(batch_size=1)
54        if not ap_batch:
55            raise RuntimeError('Unable to lock AP %r' % self.AP_SPEC)
56        self.ap = ap_batch[0]
57        # Use a development webdriver server
58        self.ap.webdriver_port = 9516
59        if not self.OVERRIDE_POWER:
60            print('Powering up the AP (this may take a minute...)')
61            self.ap._power_up_router()
62        else:
63            print('Assuming AP is not, skipping power on.')
64            self.ap.router_on = True
65
66
67    @classmethod
68    def tearDownClass(self):
69        if self.batch_locker:
70            self.batch_locker.unlock_aps()
71        if not self.OVERRIDE_POWER:
72            self.ap._power_down_router()
73
74
75    def setUp(self):
76        # All tests have to have a band pre-set.
77        bands = self.ap.get_supported_bands()
78        self.ap.set_band(bands[0]['band'])
79        self.ap.apply_settings()
80
81
82    def disabled_security_on_all_bands(self):
83        """Disables security on all available bands."""
84        for band in self.ap.get_supported_bands():
85            self.ap.set_band(band['band'])
86            self.ap.set_security_disabled()
87            self.ap.apply_settings()
88
89
90    def return_non_n_mode_pair(self):
91        """Returns a mode and band that do not contain wireless mode N.
92
93        Wireless N does not support several wifi security modes.  In order
94        to test they can be configured that makes it easy to select an
95        available compatible mode.
96        """
97        # Make this return something that does not contain N
98        return_dict = {}
99        for mode in self.ap.get_supported_modes():
100            return_dict['band'] = mode['band']
101            for mode_type in mode['modes']:
102                if (mode_type & ap_spec.MODE_N) != ap_spec.MODE_N:
103                    return_dict['mode'] = mode_type
104                else:
105                    raise RuntimeError('No modes without MODE_N')
106        return return_dict
107
108
109    def test_make_no_changes(self):
110        """Test saving with no changes doesn't throw an error."""
111        # Set to a known state.
112        self.ap.set_radio(enabled=True)
113        self.ap.apply_settings()
114        # Set the same setting again.
115        self.ap.set_radio(enabled=True)
116        self.ap.apply_settings()
117
118
119    def test_radio(self):
120        """Test we can adjust the radio setting."""
121        self.ap.set_radio(enabled=True)
122        self.ap.apply_settings()
123        self.ap.set_radio(enabled=False)
124        self.ap.apply_settings()
125
126
127    def test_channel(self):
128        """Test adjusting the channel."""
129        supported_bands = self.ap.get_supported_bands()
130        for band in supported_bands:
131            self.ap.set_band(band['band'])
132            # Set to the second available channel
133            self.ap.set_channel(band['channels'][1])
134            self.ap.apply_settings()
135
136
137    def test_visibility(self):
138        """Test adjusting the visibility."""
139        if not self.ap.is_visibility_supported():
140            return
141        self.ap.set_visibility(False)
142        self.ap.apply_settings()
143        self.ap.set_visibility(True)
144        self.ap.apply_settings()
145
146
147    def test_ssid(self):
148        """Test setting the SSID."""
149        bands_info = self.ap.get_supported_bands()
150        self.assertTrue(bands_info, msg='Invalid band sent.')
151        ssid = 'ssid2'
152        for bands in bands_info:
153            band = bands['band']
154            if band == ap_spec.BAND_5GHZ:
155                ssid = 'ssid5'
156            self.ap.set_band(band)
157            self.ap.set_ssid(ssid)
158            self.ap.apply_settings()
159        self.assertEqual(ssid, self.ap.ssid)
160
161
162    def test_band(self):
163        """Test switching the band."""
164        self.ap.set_band(ap_spec.BAND_2GHZ)
165        self.ap.apply_settings()
166        self.ap.set_band(ap_spec.BAND_5GHZ)
167        self.ap.apply_settings()
168
169
170    def test_switching_bands_and_change_settings(self):
171        """Test switching between bands and change settings for each band."""
172        bands_info = self.ap.get_supported_bands()
173        self.assertTrue(bands_info, msg='Invalid band sent.')
174        bands_set = [d['band'] for d in bands_info]
175        for band in bands_set:
176            self.ap.set_band(band)
177            self.ap.set_ssid('pqrstu_' + band)
178            if self.ap.is_visibility_supported():
179                self.ap.set_visibility(True)
180            if self.ap.is_security_mode_supported(ap_spec.SECURITY_TYPE_WEP):
181                self.ap.set_security_wep('test2',
182                                         ap_spec.WEP_AUTHENTICATION_OPEN)
183            self.ap.apply_settings()
184
185
186    def test_invalid_security(self):
187        """Test an exception is thrown for an invalid configuration."""
188        self.disabled_security_on_all_bands()
189        for mode in self.ap.get_supported_modes():
190            if not ap_spec.MODE_N in mode['modes']:
191                return
192        if not self.ap.is_security_mode_supported(ap_spec.SECURITY_TYPE_WEP):
193            return
194        self.ap.set_mode(ap_spec.MODE_N)
195        self.ap.set_security_wep('77777', ap_spec.WEP_AUTHENTICATION_OPEN)
196        try:
197            self.ap.apply_settings()
198        except RuntimeError, e:
199            self.ap.driver.close()
200            message = str(e)
201            if message.find('no handler was specified') != -1:
202                self.fail('Subclass did not handle an alert.')
203            return
204        self.fail('An exception should have been thrown but was not.')
205
206
207    def test_security_wep(self):
208        """Test configuring WEP security."""
209        if not self.ap.is_security_mode_supported(ap_spec.SECURITY_TYPE_WEP):
210            return
211        for mode in self.ap.get_supported_modes():
212            self.ap.set_band(mode['band'])
213            for mode_type in mode['modes']:
214                if mode_type & ap_spec.MODE_N != ap_spec.MODE_N:
215                    self.ap.set_mode(mode_type)
216                    self.ap.set_security_wep('45678',
217                                             ap_spec.WEP_AUTHENTICATION_OPEN)
218                    self.ap.apply_settings()
219                    self.ap.set_security_wep('90123',
220                                             ap_spec.WEP_AUTHENTICATION_SHARED)
221                    self.ap.apply_settings()
222
223
224    def test_priority_sets(self):
225        """Test that commands are run in the right priority."""
226        self.ap.set_radio(enabled=False)
227        if self.ap.is_visibility_supported():
228            self.ap.set_visibility(True)
229        self.ap.set_ssid('prioritytest')
230        self.ap.apply_settings()
231
232
233    def test_security_and_general_settings(self):
234        """Test updating settings that are general and security related."""
235        self.disabled_security_on_all_bands()
236        try:
237            good_pair = self.return_non_n_mode_pair()
238            self.ap.set_radio(enabled=False)
239            self.ap.set_band(good_pair['band'])
240            self.ap.set_mode(good_pair['mode'])
241        except RuntimeError:
242            # AP does not support modes without MODE_N
243            return
244        if self.ap.is_visibility_supported():
245            self.ap.set_visibility(True)
246        if self.ap.is_security_mode_supported(ap_spec.SECURITY_TYPE_WEP):
247            self.ap.set_security_wep('88888', ap_spec.WEP_AUTHENTICATION_OPEN)
248        self.ap.set_ssid('secgentest')
249        self.ap.apply_settings()
250
251
252    def test_modes(self):
253        """Tests switching modes."""
254        # Some security settings won't work with some modes
255        self.ap.set_security_disabled()
256        self.ap.apply_settings()
257        modes_info = self.ap.get_supported_modes()
258        self.assertTrue(modes_info,
259                        msg='Returned an invalid mode list.  Is this method'
260                        ' implemented?')
261        for band_modes in modes_info:
262            self.ap.set_band(band_modes['band'])
263            for mode in band_modes['modes']:
264                self.ap.set_mode(mode)
265                self.ap.apply_settings()
266
267
268    def test_modes_with_band(self):
269        """Tests switching modes that support adjusting the band."""
270        # Different bands and security options conflict.  Disable security for
271        # this test.
272        self.disabled_security_on_all_bands()
273        # Check if we support self.kModeN across multiple bands
274        modes_info = self.ap.get_supported_modes()
275        n_bands = []
276        for band_modes in modes_info:
277            if ap_spec.MODE_N in band_modes['modes']:
278                n_bands.append(band_modes['band'])
279        if len(n_bands) > 1:
280            for n_band in n_bands:
281                self.ap.set_mode(ap_spec.MODE_N, band=n_band)
282                self.ap.apply_settings()
283
284
285    def test_fast_cycle_security(self):
286        """Mini stress for changing security settings rapidly."""
287        self.disabled_security_on_all_bands()
288        self.ap.set_radio(enabled=True)
289        if self.ap.is_security_mode_supported(ap_spec.SECURITY_TYPE_WEP):
290            self.ap.set_security_wep('77777', ap_spec.WEP_AUTHENTICATION_OPEN)
291        if self.ap.is_security_mode_supported(ap_spec.SECURITY_TYPE_DISABLED):
292            self.ap.set_security_disabled()
293        if self.ap.is_security_mode_supported(ap_spec.SECURITY_TYPE_WPAPSK):
294            self.ap.set_security_wpapsk(ap_spec.SECURITY_TYPE_WPAPSK,
295                                        'qwertyuiolkjhgfsdfg')
296        self.ap.apply_settings()
297
298
299    def test_cycle_security(self):
300        """Test switching between different security settings."""
301        self.disabled_security_on_all_bands()
302        try:
303            good_pair = self.return_non_n_mode_pair()
304            self.ap.set_radio(enabled=True)
305            self.ap.set_band(good_pair['band'])
306            self.ap.set_mode(good_pair['mode'])
307        except RuntimeError:
308            # AP does not support modes without MODE_N
309            return
310        if self.ap.is_security_mode_supported(ap_spec.SECURITY_TYPE_WEP):
311            self.ap.set_security_wep('77777', ap_spec.WEP_AUTHENTICATION_OPEN)
312        self.ap.apply_settings()
313        if self.ap.is_security_mode_supported(ap_spec.SECURITY_TYPE_DISABLED):
314            self.ap.set_security_disabled()
315        self.ap.apply_settings()
316        if self.ap.is_security_mode_supported(ap_spec.SECURITY_TYPE_WPA2PSK):
317            self.ap.set_security_wpapsk(ap_spec.SECURITY_TYPE_WPA2PSK,
318                                        'qwertyuiolkjhgfsdfg')
319        self.ap.apply_settings()
320
321
322    def test_actions_when_radio_disabled(self):
323        """Test making changes when the radio is disabled."""
324        self.disabled_security_on_all_bands()
325        try:
326            good_pair = self.return_non_n_mode_pair()
327            self.ap.set_radio(enabled=False)
328            self.ap.set_band(good_pair['band'])
329            self.ap.set_mode(good_pair['mode'])
330        except RuntimeError:
331            # AP does not support modes without MODE_N
332            return
333        self.ap.apply_settings()
334        if self.ap.is_security_mode_supported(ap_spec.SECURITY_TYPE_WEP):
335            self.ap.set_security_wep('77777', ap_spec.WEP_AUTHENTICATION_OPEN)
336        self.ap.set_radio(enabled=False)
337        self.ap.apply_settings()
338
339
340    def test_configuring_with_ap_spec(self):
341        """Test configuring the AP using an APSpec."""
342        spec = ap_spec.APSpec()
343        self.ap.set_using_ap_spec(spec)
344        self.ap.apply_settings()
345
346
347    def test_power_cycle_router(self):
348        """Test powering the ap down and back up again."""
349        self.ap.power_cycle_router_up()
350
351
352if __name__ == '__main__':
353    unittest.main()
354