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"""Base class for NetgearWNDR dual band routers."""
6
7import urlparse
8import dynamic_ap_configurator
9import ap_spec
10
11from selenium.common.exceptions import TimeoutException as \
12    SeleniumTimeoutException
13
14
15class NetgearDualBandAPConfigurator(
16        dynamic_ap_configurator.DynamicAPConfigurator):
17    """Base class for NetgearWNDR dual band routers."""
18
19
20    def _alert_handler(self, alert):
21        """Checks for any modal dialogs which popup to alert the user and
22        either raises a RuntimeError or ignores the alert.
23
24        Args:
25          alert: The modal dialog's contents.
26        """
27        text = alert.text
28        if 'WPA-PSK [TKIP] ONLY operates at \"Up to 54Mbps\"' in text:
29            alert.accept()
30            raise RuntimeError('Wrong mode selected. %s' % text)
31        elif '2.4G and 5G have the same SSID' in text:
32            alert.accept()
33            raise RuntimeError('%s. Please change the SSID of one band' % text)
34        elif 'do not want any wireless security on your network?' in text:
35            alert.accept()
36        elif 'recommends that you set the router to a high channel' in text:
37            alert.accept()
38        elif 'security authentication cannot work with WPS' in text:
39            alert.accept()
40        elif 'WPS requires SSID broadcasting in order to work' in text:
41            alert.accept()
42        else:
43            raise RuntimeError('We have an unhandled alert on AP %s: %s' %
44                               (self.host_name, text))
45
46
47    def get_number_of_pages(self):
48        return 1
49
50
51    def is_update_interval_supported(self):
52        """Returns True if setting the PSK refresh interval is supported.
53
54        @return True is supported; False otherwise
55        """
56        return False
57
58
59    def get_supported_bands(self):
60        return [{'band': ap_spec.BAND_2GHZ,
61                 'channels': ['Auto', 1, 2, 3, 4, 5, 6, 7, 8, 9 , 10, 11]},
62                {'band': ap_spec.BAND_5GHZ,
63                 'channels': ['Auto', 36, 40, 44, 48, 149, 153,
64                              157, 161, 165]}]
65
66
67    def get_supported_modes(self):
68        return [{'band': ap_spec.BAND_2GHZ,
69                 'modes': [ap_spec.MODE_G, ap_spec.MODE_N]},
70                {'band': ap_spec.BAND_5GHZ,
71                 'modes': [ap_spec.MODE_A, ap_spec.MODE_N]}]
72
73
74    def is_security_mode_supported(self, security_mode):
75        """Returns if the supported security modes.
76
77        @param security_mode: the security mode to check against
78
79        """
80        return security_mode in (ap_spec.SECURITY_TYPE_DISABLED,
81                                 ap_spec.SECURITY_TYPE_WPAPSK,
82                                 ap_spec.SECURITY_TYPE_WPA2PSK,
83                                 ap_spec.SECURITY_TYPE_WEP)
84
85
86    def navigate_to_page(self, page_number):
87        """Navigates to the given page.
88
89        @param page_number: page number to open as an iteger
90
91        """
92        if page_number != 1:
93            raise RuntimeError('Invalid page number passed.  Number of pages '
94                               '%d, page value sent was %d' %
95                               (self.get_number_of_pages(), page_number))
96        page_url = urlparse.urljoin(self.admin_interface_url,
97                                    'WLG_wireless_dual_band.htm')
98        try:
99            for i in range(5):
100                self.get_url(page_url, page_title='NETGEAR Router')
101                if 'NETGEAR Router' in self.driver.title:
102                    break
103        except SeleniumTimeoutException, e:
104            xpath = '//button[@name="yes" and @class="purpleBtn"]'
105            for i in range(5):
106                element = self.wait_for_object_by_xpath(xpath)
107                if element and element.is_displayed():
108                    self.click_button_by_xpath(xpath)
109                    break
110            else:
111                self.driver.refresh()
112        self.wait_for_object_by_xpath('//input[@name="ssid" and @type="text"]')
113
114
115    def save_page(self, page_number):
116        """Saves all settings.
117
118        @param page_number: the page to save.
119
120        """
121        self.click_button_by_xpath('//button[@name="Apply"]',
122                                   alert_handler=self._alert_handler)
123
124
125    def set_mode(self, mode, band=None):
126        # The mode popup changes based on the security mode.  Set to no
127        # security to get the right popup.
128        self.add_item_to_command_list(self._set_security_disabled, (), 1, 600)
129        self.add_item_to_command_list(self._set_mode, (mode, ), 1, 700)
130
131
132    def _set_mode(self, mode, band=None):
133        if mode == ap_spec.MODE_G or mode == ap_spec.MODE_A:
134            mode = 'Up to 54 Mbps'
135        elif mode == ap_spec.MODE_N:
136            mode = 'Up to 300 Mbps'
137        else:
138            raise RuntimeError('Unsupported mode passed.')
139        xpath = '//select[@name="opmode"]'
140        if self.current_band == ap_spec.BAND_5GHZ:
141            xpath = '//select[@name="opmode_an"]'
142        self.wait_for_object_by_xpath(xpath)
143        self.select_item_from_popup_by_xpath(mode, xpath,
144                                             alert_handler=self._alert_handler)
145
146
147    def set_radio(self, enabled=True):
148        #  We cannot turn off the radio in Netgear
149        return None
150
151
152    def set_ssid(self, ssid):
153        self.add_item_to_command_list(self._set_ssid, (ssid,), 1, 900)
154
155
156    def _set_ssid(self, ssid):
157        xpath = '//input[@name="ssid"]'
158        if self.current_band == ap_spec.BAND_5GHZ:
159            xpath = '//input[@name="ssid_an"]'
160        self.set_content_of_text_field_by_xpath(ssid, xpath)
161        self._ssid = ssid
162
163
164    def set_channel(self, channel):
165        self.add_item_to_command_list(self._set_channel, (channel,), 1, 800)
166
167
168    def _set_channel(self, channel):
169        position = self._get_channel_popup_position(channel)
170        channel_choices = ['Auto', '01', '02', '03', '04', '05', '06', '07',
171                           '08', '09', '10', '11']
172        xpath = '//select[@name="w_channel"]'
173        if self.current_band == ap_spec.BAND_5GHZ:
174            xpath = '//select[@name="w_channel_an"]'
175            channel_choices = ['Auto', '36', '40', '44', '48', '149', '153',
176                               '157', '161', '165']
177        self.select_item_from_popup_by_xpath(channel_choices[position],
178                                             xpath,
179                                             alert_handler=self._alert_handler)
180
181
182    def set_band(self, band):
183        if band == ap_spec.BAND_5GHZ:
184            self.current_band = ap_spec.BAND_5GHZ
185        elif band == ap_spec.BAND_2GHZ:
186            self.current_band = ap_spec.BAND_2GHZ
187        else:
188            raise RuntimeError('Invalid band sent %s' % band)
189
190
191    def set_security_disabled(self):
192        self.add_item_to_command_list(self._set_security_disabled, (), 1, 1000)
193
194
195    def _set_security_disabled(self):
196        xpath = '//input[@name="security_type"]'
197        if self.current_band == ap_spec.BAND_5GHZ:
198            xpath = '//input[@name="security_type_an"]'
199        self.click_button_by_xpath(xpath, alert_handler=self._alert_handler)
200
201
202    def set_security_wep(self, key_value, authentication):
203        # The button name seems to differ in various Netgear routers
204        self.add_item_to_command_list(self._set_security_wep,
205                                      (key_value, authentication), 1, 1000)
206
207
208    def _set_security_wep(self, key_value, authentication):
209        xpath = '//input[@name="security_type" and @value="WEP" and\
210                 @type="radio"]'
211        text_field = '//input[@name="passphraseStr"]'
212        button = '//button[@name="keygen"]'
213        if self.current_band == ap_spec.BAND_5GHZ:
214            xpath = '//input[@name="security_type_an" and @value="WEP" and\
215                     @type="radio"]'
216            text_field = '//input[@name="passphraseStr_an"]'
217            button = '//button[@name="Generate_an"]'
218        try:
219            self.wait_for_object_by_xpath(xpath)
220            self.click_button_by_xpath(xpath, alert_handler=self._alert_handler)
221        except Exception, e:
222            raise RuntimeError('We got an exception: "%s". Check the mode. '
223                               'It should be \'Up to 54 Mbps\'.' % str(e))
224        self.wait_for_object_by_xpath(text_field)
225        self.set_content_of_text_field_by_xpath(key_value, text_field,
226                                                abort_check=True)
227        self.click_button_by_xpath(button, alert_handler=self._alert_handler)
228
229
230    def set_security_wpapsk(self, security, shared_key, update_interval=None):
231        self.add_item_to_command_list(self._set_security_wpapsk,
232                                      (security, shared_key,), 1, 1000)
233
234
235    def _set_security_wpapsk(self, security, shared_key, update_interval=None):
236        # Update Interval is not supported.
237        if security == ap_spec.SECURITY_TYPE_WPAPSK:
238            wpa_item = "WPA-PSK"
239            # WPA-PSK is supported only in mode g and a (Up to 54 Mbps).
240            # Setting correct mode before setting WPA-PSK.
241            if self.current_band == ap_spec.BAND_2GHZ:
242                self._set_mode(ap_spec.MODE_G, self.current_band)
243            else:
244                self._set_mode(ap_spec.MODE_A, self.current_band)
245        else:
246            wpa_item = "WPA2-PSK"
247        xpath = ('//input[@name="security_type" and @value="%s"]' % wpa_item)
248        text = '//input[@name="passphrase"]'
249        if self.current_band == ap_spec.BAND_5GHZ:
250            xpath = ('//input[@name="security_type_an" and @value="%s"]' %
251                              wpa_item)
252            text = '//input[@name="passphrase_an"]'
253        try:
254            self.click_button_by_xpath(xpath,
255                                       alert_handler=self._alert_handler)
256        except Exception, e:
257            raise RuntimeError('For WPA-PSK the mode should be 54Mbps. %s' % e)
258        self.set_content_of_text_field_by_xpath(shared_key, text,
259                                                abort_check=True)
260
261
262    def set_visibility(self, visible=True):
263        # This router is very fussy with WPS even if it is not enabled.  It
264        # throws an alert if visibility is off before you adjust security.
265        # Bump visibilities priority to avoid that warning.
266        self.add_item_to_command_list(self._set_visibility, (visible,), 1, 500)
267
268
269    def _set_visibility(self, visible=True):
270        xpath = '//input[@name="ssid_bc" and @type="checkbox"]'
271        if self.current_band == ap_spec.BAND_5GHZ:
272            xpath = '//input[@name="ssid_bc_an" and @type="checkbox"]'
273        check_box = self.wait_for_object_by_xpath(xpath)
274        # These check boxes behave different from other APs.
275        value = check_box.is_selected()
276        if (visible and not value) or (not visible and value):
277            self.click_button_by_xpath(xpath, alert_handler=self._alert_handler)
278