1#!/usr/bin/env python3.4
2#
3#   Copyright 2016 - The Android Open Source Project
4#
5#   Licensed under the Apache License, Version 2.0 (the "License");
6#   you may not use this file except in compliance with the License.
7#   You may obtain a copy of 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,
13#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14#   See the License for the specific language governing permissions and
15#   limitations under the License.
16
17import time
18
19from acts import asserts
20from acts import base_test
21from acts.test_utils.wifi import wifi_constants
22from acts.test_utils.wifi import wifi_test_utils as wutils
23
24WifiEnums = wutils.WifiEnums
25NETWORK_ID_ERROR = "Network don't have ID"
26NETWORK_ERROR = "Device is not connected to reference network"
27
28
29class WifiAutoJoinTest(base_test.BaseTestClass):
30    def __init__(self, controllers):
31        base_test.BaseTestClass.__init__(self, controllers)
32        self.tests = ("test_autojoin_out_of_range",
33                      "test_autojoin_Ap1_2g",
34                      "test_autojoin_Ap1_2gto5g",
35                      "test_autojoin_in_AP1_5gto2g",
36                      "test_autojoin_swtich_AP1toAp2",
37                      "test_autojoin_Ap2_2gto5g",
38                      "test_autojoin_Ap2_5gto2g",
39                      "test_autojoin_out_of_range",
40                      "test_autojoin_Ap2_2g",
41                      "test_autojoin_Ap2_2gto5g",
42                      "test_autojoin_in_Ap2_5gto2g",
43                      "test_autojoin_swtich_AP2toAp1",
44                      "test_autojoin_Ap1_2gto5g",
45                      "test_autojoin_Ap1_5gto2g",
46                      "test_autojoin_swtich_to_blacklist_AP",
47                      "test_autojoin_in_blacklist_AP",
48                      "test_autojoin_back_from_blacklist_AP", )
49
50    def setup_class(self):
51        """It will setup the required dependencies from config file and configure
52           the required networks for auto-join testing. Configured networks will
53           not be removed. If networks are already configured it will skip
54           configuring the networks
55
56        Returns:
57            True if successfully configured the requirements for testing.
58        """
59        self.dut = self.android_devices[0]
60        wutils.wifi_test_device_init(self.dut)
61        req_params = ("reference_networks", "other_network", "atten_val",
62                      "ping_addr", "max_bugreports")
63        self.unpack_userparams(req_params)
64        self.log.debug("Connect networks :: {}".format(self.other_network))
65        configured_networks = self.dut.droid.wifiGetConfiguredNetworks()
66        self.log.debug("Configured networks :: {}".format(configured_networks))
67        count_confnet = 0
68        result = False
69        if self.reference_networks[0]['2g']['ssid'] == self.reference_networks[
70                0]['5g']['ssid']:
71            self.ref_ssid_count = 1
72        else:
73            self.ref_ssid_count = 2  # Different SSID for 2g and 5g
74        for confnet in configured_networks:
75            if confnet[WifiEnums.SSID_KEY] == self.reference_networks[0]['2g'][
76                    'ssid']:
77                count_confnet += 1
78            elif confnet[WifiEnums.SSID_KEY] == self.reference_networks[0][
79                    '5g']['ssid']:
80                count_confnet += 1
81        self.log.info("count_confnet {}".format(count_confnet))
82        if count_confnet == self.ref_ssid_count:
83            return
84        else:
85            self.log.info("Configured networks for testing")
86            self.attenuators[0].set_atten(0)
87            self.attenuators[1].set_atten(90)
88            self.attenuators[2].set_atten(90)
89            wait_time = 15
90            self.dut.droid.wakeLockAcquireBright()
91            self.dut.droid.wakeUpNow()
92            try:
93                self.dut.droid.wifiConnectByConfig(self.reference_networks[0][
94                    '2g'])
95                connect_result = self.dut.ed.pop_event(
96                    wifi_constants.CONNECT_BY_CONFIG_SUCCESS, 1)
97                self.log.info(connect_result)
98                time.sleep(wait_time)
99                if self.ref_ssid_count == 2:  #add 5g network as well
100                    self.dut.droid.wifiConnectByConfig(self.reference_networks[
101                        0]['5g'])
102                    connect_result = self.dut.ed.pop_event(
103                        wifi_constants.CONNECT_BY_CONFIG_SUCCESS, 1)
104                    self.log.info(connect_result)
105                    time.sleep(wait_time)
106                self.dut.droid.wifiConnectByConfig(self.other_network)
107                connect_result = self.dut.ed.pop_event(
108                    wifi_constants.CONNECT_BY_CONFIG_SUCCESS)
109                self.log.info(connect_result)
110                wutils.track_connection(self.dut, self.other_network["ssid"], 1)
111                wutils.wifi_forget_network(self.dut, self.other_network["ssid"])
112                time.sleep(wait_time)
113                current_network = self.dut.droid.wifiGetConnectionInfo()
114                self.log.info("Current network: {}".format(current_network))
115                asserts.assert_true('network_id' in current_network,
116                                    NETWORK_ID_ERROR)
117                asserts.assert_true(current_network['network_id'] >= 0,
118                                    NETWORK_ERROR)
119            finally:
120                self.dut.droid.wifiLockRelease()
121                self.dut.droid.goToSleepNow()
122
123    def check_connection(self, network_bssid):
124        """Check current wifi connection networks.
125        Args:
126            network_bssid: Network bssid to which connection.
127        Returns:
128            True if connection to given network happen, else return False.
129        """
130        time.sleep(40)  #time for connection state to be updated
131        self.log.info("Check network for {}".format(network_bssid))
132        current_network = self.dut.droid.wifiGetConnectionInfo()
133        self.log.debug("Current network:  {}".format(current_network))
134        if WifiEnums.BSSID_KEY in current_network:
135            return current_network[WifiEnums.BSSID_KEY] == network_bssid
136        return False
137
138    def set_attn_and_validate_connection(self, attn_value, bssid):
139        """Validate wifi connection status on different attenuation setting.
140
141        Args:
142            attn_value: Attenuation value for different APs signal.
143            bssid: Bssid of excepted network.
144
145        Returns:
146            True if bssid of current network match, else false.
147        """
148        self.attenuators[0].set_atten(attn_value[0])
149        self.attenuators[1].set_atten(attn_value[1])
150        self.attenuators[2].set_atten(attn_value[2])
151        self.dut.droid.wakeLockAcquireBright()
152        self.dut.droid.wakeUpNow()
153        try:
154            asserts.assert_true(
155                self.check_connection(bssid),
156                "Device is not connected to required bssid {}".format(bssid))
157            time.sleep(10)  #wait for connection to be active
158            asserts.assert_true(
159                wutils.validate_connection(self.dut, self.ping_addr),
160                "Error, No Internet connection for current bssid {}".format(
161                    bssid))
162        finally:
163            self.dut.droid.wifiLockRelease()
164            self.dut.droid.goToSleepNow()
165
166    def on_fail(self, test_name, begin_time):
167        if self.max_bugreports > 0:
168            self.dut.take_bug_report(test_name, begin_time)
169            self.max_bugreports -= 1
170        self.dut.cat_adb_log(test_name, begin_time)
171
172    """ Tests Begin """
173
174    def test_autojoin_Ap1_2g(self):
175        """Test wifi auto join functionality move in range of AP1.
176
177         1. Attenuate the signal to low range of AP1 and Ap2 not visible at all.
178         2. Wake up the device.
179         3. Check that device is connected to right BSSID and maintain stable
180            connection to BSSID in range.
181        """
182        att0, att1, att2 = self.atten_val["Ap1_2g"]
183        variance = 5
184        attenuations = ([att0 + variance * 2, att1, att2],
185                        [att0 + variance, att1, att2], [att0, att1, att2],
186                        [att0 - variance, att1, att2])
187        name_func = lambda att_value, bssid: ("test_autojoin_Ap1_2g_AP1_{}_AP2"
188                                              "_{}_AP3_{}").format(att_value[0], att_value[1], att_value[2])
189        failed = self.run_generated_testcases(
190            self.set_attn_and_validate_connection,
191            attenuations,
192            args=(self.reference_networks[0]["2g"]['bssid'], ),
193            name_func=name_func)
194        asserts.assert_false(
195            failed,
196            "Number of test_autojoin_Ap1_2g failed {}".format(len(failed)))
197
198    def test_autojoin_Ap1_2gto5g(self):
199        """Test wifi auto join functionality move to high range.
200
201         1. Attenuate the signal to high range of AP1.
202         2. Wake up the device.
203         3. Check that device is connected to right BSSID and maintain stable
204            connection to BSSID in range.
205        """
206        att0, att1, att2 = self.atten_val["Ap1_2gto5g"]
207        variance = 5
208        attenuations = ([att0 + variance * 2, att1, att2],
209                        [att0 + variance, att1, att2], [att0, att1, att2])
210        name_func = lambda att_value, bssid: ("test_autojoin_Ap1_2gto5g_AP1_{}_AP2"
211                                              "_{}_AP3_{}").format(att_value[0], att_value[1], att_value[2])
212        failed = self.run_generated_testcases(
213            self.set_attn_and_validate_connection,
214            attenuations,
215            args=(self.reference_networks[0]["5g"]['bssid'], ),
216            name_func=name_func)
217        asserts.assert_false(
218            failed,
219            "Number of test_autojoin_Ap1_2gto5g failed {}".format(len(failed)))
220
221    def test_autojoin_in_AP1_5gto2g(self):
222        """Test wifi auto join functionality move to low range toward AP2.
223
224         1. Attenuate the signal to medium range of AP1 and low range of AP2.
225         2. Wake up the device.
226         3. Check that device is connected to right BSSID and maintain stable
227            connection to BSSID in range.
228        """
229        att0, att1, att2 = self.atten_val["In_AP1_5gto2g"]
230        variance = 5
231        attenuations = ([att0 - variance, att1 + variance, att2],
232                        [att0, att1, att2],
233                        [att0 + variance, att1 - variance, att2])
234        name_func = lambda att_value, bssid: ("test_autojoin_in_AP1_5gto2g_AP1_{}_AP2"
235                                              "_{}_AP3_{}").format(att_value[0], att_value[1], att_value[2])
236        failed = self.run_generated_testcases(
237            self.set_attn_and_validate_connection,
238            attenuations,
239            args=(self.reference_networks[0]["2g"]['bssid'], ),
240            name_func=name_func)
241        asserts.assert_false(
242            failed, "Number of test_autojoin_in_AP1_5gto2g failed {}".format(
243                len(failed)))
244
245    def test_autojoin_swtich_AP1toAp2(self):
246        """Test wifi auto join functionality move from low range of AP1 to better
247           range of AP2.
248
249         1. Attenuate the signal to low range of AP1 and medium range of AP2.
250         2. Wake up the device.
251         3. Check that device is connected to right BSSID and maintain stable
252            connection to BSSID in range.
253        """
254        att0, att1, att2 = self.atten_val["Swtich_AP1toAp2"]
255        variance = 5
256        attenuations = ([att0 - variance, att1 + variance, att2],
257                        [att0, att1, att2],
258                        [att0 + variance, att1 - variance, att2])
259        name_func = lambda att_value, bssid: ("test_autojoin_swtich_AP1toAp2_AP1_{}_AP2"
260                                              "_{}_AP3_{}").format(att_value[0], att_value[1], att_value[2])
261        failed = self.run_generated_testcases(
262            self.set_attn_and_validate_connection,
263            attenuations,
264            args=(self.reference_networks[1]["2g"]['bssid'], ),
265            name_func=name_func)
266        asserts.assert_false(
267            failed, "Number of test_autojoin_swtich_AP1toAp2 failed {}".format(
268                len(failed)))
269
270    def test_autojoin_Ap2_2gto5g(self):
271        """Test wifi auto join functionality move to high range of AP2.
272
273         1. Attenuate the signal to out range of AP1 and high range of AP2.
274         2. Wake up the device.
275         3. Check that device is connected to right BSSID and maintain stable
276            connection to BSSID in range.
277        """
278        att0, att1, att2 = self.atten_val["Ap2_2gto5g"]
279        variance = 5
280        attenuations = ([att0 - variance, att1 + variance * 2, att2],
281                        [att0, att1 + variance, att2], [att0, att1, att2])
282        name_func = lambda att_value, bssid: ("test_autojoin_Ap2_2gto5g_AP1_{}_AP2"
283                                              "_{}_AP3_{}").format(att_value[0], att_value[1], att_value[2])
284        failed = self.run_generated_testcases(
285            self.set_attn_and_validate_connection,
286            attenuations,
287            args=(self.reference_networks[1]["5g"]['bssid'], ),
288            name_func=name_func)
289        asserts.assert_false(
290            failed,
291            "Number of test_autojoin_Ap2_2gto5g failed {}".format(len(failed)))
292
293    def test_autojoin_Ap2_5gto2g(self):
294        """Test wifi auto join functionality move to low range of AP2.
295
296         1. Attenuate the signal to low range of AP2.
297         2. Wake up the device.
298         3. Check that device is connected to right BSSID and maintain stable.
299        """
300        att0, att1, att2 = self.atten_val["Ap2_5gto2g"]
301        variance = 5
302        attenuations = ([att0, att1 - variance, att2], [att0, att1, att2],
303                        [att0, att1 + variance, att2])
304        name_func = lambda att_value, bssid: ("test_autojoin_Ap2_5gto2g_AP1_{}_AP2"
305                                              "_{}_AP3_{}").format(att_value[0], att_value[1], att_value[2])
306        failed = self.run_generated_testcases(
307            self.set_attn_and_validate_connection,
308            attenuations,
309            args=(self.reference_networks[1]["2g"]['bssid'], ),
310            name_func=name_func)
311        asserts.assert_false(
312            failed,
313            "Number of test_autojoin_Ap2_5gto2g failed {}".format(len(failed)))
314
315    def test_autojoin_out_of_range(self):
316        """Test wifi auto join functionality move to low range.
317
318         1. Attenuate the signal to out of range.
319         2. Wake up the device.
320         3. Start the scan.
321         4. Check that device is not connected to any network.
322        """
323        self.attenuators[0].set_atten(90)
324        self.attenuators[1].set_atten(90)
325        self.attenuators[2].set_atten(90)
326        self.dut.droid.wakeLockAcquireBright()
327        self.dut.droid.wakeUpNow()
328        try:
329            wutils.start_wifi_connection_scan(self.dut)
330            wifi_results = self.dut.droid.wifiGetScanResults()
331            self.log.debug("Scan result {}".format(wifi_results))
332            time.sleep(20)
333            current_network = self.dut.droid.wifiGetConnectionInfo()
334            self.log.info("Current network: {}".format(current_network))
335            asserts.assert_true(
336                ('network_id' in current_network and
337                 current_network['network_id'] == -1),
338                "Device is connected to network {}".format(current_network))
339        finally:
340            self.dut.droid.wifiLockRelease()
341            self.dut.droid.goToSleepNow()
342
343    def test_autojoin_Ap2_2g(self):
344        """Test wifi auto join functionality move in low range of AP2.
345
346         1. Attenuate the signal to move in range of AP2 and Ap1 not visible at all.
347         2. Wake up the device.
348         3. Check that device is connected to right BSSID and maintain stable
349            connection to BSSID in range.
350        """
351        att0, att1, att2 = self.atten_val["Ap2_2g"]
352        variance = 5
353        attenuations = ([att0, att1 + variance * 2, att2],
354                        [att0, att1 + variance, att2], [att0, att1, att2],
355                        [att0, att1 - variance, att2])
356        name_func = lambda att_value, bssid: ("test_autojoin_Ap2_2g_AP1_{}_AP2"
357                                              "_{}_AP3_{}").format(att_value[0], att_value[1], att_value[2])
358        failed = self.run_generated_testcases(
359            self.set_attn_and_validate_connection,
360            attenuations,
361            args=(self.reference_networks[1]["2g"]['bssid'], ),
362            name_func=name_func)
363        asserts.assert_false(
364            failed,
365            "Number of test_autojoin_Ap2_2g failed {}".format(len(failed)))
366
367    def test_autojoin_in_Ap2_5gto2g(self):
368        """Test wifi auto join functionality move to medium range of Ap2 and
369           low range of AP1.
370
371         1. Attenuate the signal to move in medium range of AP2 and low range of AP1.
372         2. Wake up the device.
373         3. Check that device is connected to right BSSID and maintain stable
374            connection to BSSID in range.
375        """
376        att0, att1, att2 = self.atten_val["In_Ap2_5gto2g"]
377        variance = 5
378        attenuations = ([att0, att1 - variance, att2], [att0, att1, att2],
379                        [att0, att1 + variance, att2])
380        name_func = lambda att_value, bssid: ("test_autojoin_in_Ap2_5gto2g_AP1_{}_AP2"
381                                              "_{}_AP3_{}").format(att_value[0], att_value[1], att_value[2])
382        failed = self.run_generated_testcases(
383            self.set_attn_and_validate_connection,
384            attenuations,
385            args=(self.reference_networks[1]["2g"]['bssid'], ),
386            name_func=name_func)
387        asserts.assert_false(
388            failed, "Number of test_autojoin_in_Ap2_5gto2g failed {}".format(
389                len(failed)))
390
391    def test_autojoin_swtich_AP2toAp1(self):
392        """Test wifi auto join functionality move from low range of AP2 to better
393           range of AP1.
394
395         1. Attenuate the signal to low range of AP2 and medium range of AP1.
396         2. Wake up the device.
397         3. Check that device is connected to right BSSID and maintain stable
398            connection to BSSID in range.
399        """
400        att0, att1, att2 = self.atten_val["Swtich_AP2toAp1"]
401        variance = 5
402        attenuations = ([att0 + variance, att1 - variance, att2],
403                        [att0, att1, att2],
404                        [att0 - variance, att1 + variance, att2])
405        name_func = lambda att_value, bssid: ("test_autojoin_swtich_AP2toAp1_AP1_{}_AP2"
406                                              "_{}_AP3_{}").format(att_value[0], att_value[1], att_value[2])
407        failed = self.run_generated_testcases(
408            self.set_attn_and_validate_connection,
409            attenuations,
410            args=(self.reference_networks[0]["2g"]['bssid'], ),
411            name_func=name_func)
412        asserts.assert_false(
413            failed, "Number of test_autojoin_swtich_AP2toAp1 failed {}".format(
414                len(failed)))
415
416    def test_autojoin_Ap1_5gto2g(self):
417        """Test wifi auto join functionality move to medium range of AP1.
418
419         1. Attenuate the signal to medium range of AP1.
420         2. Wake up the device.
421         3. Check that device is connected to right BSSID and maintain stable
422            connection to BSSID in range.
423        """
424        att0, att1, att2 = self.atten_val["Ap1_5gto2g"]
425        variance = 5
426        attenuations = ([att0, att1, att2], [att0 + variance, att1, att2],
427                        [att0 + variance * 2, att1, att2])
428        name_func = lambda att_value, bssid: ("test_autojoin_Ap1_5gto2g_AP1_{}_AP2"
429                                              "_{}_AP3_{}").format(att_value[0], att_value[1], att_value[2])
430        failed = self.run_generated_testcases(
431            self.set_attn_and_validate_connection,
432            attenuations,
433            args=(self.reference_networks[0]["2g"]['bssid'], ),
434            name_func=name_func)
435        asserts.assert_false(
436            failed,
437            "Number of test_autojoin_Ap1_5gto2g failed {}".format(len(failed)))
438
439    def test_autojoin_swtich_to_blacklist_AP(self):
440        """Test wifi auto join functionality in medium range of blacklist BSSID.
441
442         1. Attenuate the signal to low range of AP1 and medium range of AP3.
443         2. Wake up the device.
444         3. Check that device is connected to AP1 BSSID and maintain stable
445            connection to BSSID.
446        """
447        self.set_attn_and_validate_connection(
448            self.atten_val["Swtich_to_blacklist"],
449            self.reference_networks[0]["2g"]['bssid'])
450
451    def test_autojoin_in_blacklist_AP(self):
452        """Test wifi auto join functionality in high range of blacklist BSSID.
453
454         1. Attenuate the signal to out of range of AP1 and full range of AP3.
455         2. Wake up the device.
456         3. Check that device is disconnected form all AP.
457        """
458        attn0, attn1, attn2 = self.atten_val["In_blacklist"]
459        self.attenuators[0].set_atten(attn0)
460        self.attenuators[1].set_atten(attn1)
461        self.attenuators[2].set_atten(attn2)
462        self.dut.droid.wakeLockAcquireBright()
463        self.dut.droid.wakeUpNow()
464        try:
465            wutils.start_wifi_connection_scan(self.dut)
466            wifi_results = self.dut.droid.wifiGetScanResults()
467            self.log.debug("Scan result {}".format(wifi_results))
468            time.sleep(20)
469            current_network = self.dut.droid.wifiGetConnectionInfo()
470            self.log.info("Current network: {}".format(current_network))
471            asserts.assert_true(
472                ('network_id' in current_network and
473                 current_network['network_id'] == -1),
474                "Device is still connected to blacklisted network {}".format(
475                    current_network))
476        finally:
477            self.dut.droid.wifiLockRelease()
478            self.dut.droid.goToSleepNow()
479
480    def test_autojoin_back_from_blacklist_AP(self):
481        """Test wifi auto join functionality in medium range of blacklist BSSID.
482
483         1. Attenuate the signal to medium of range of AP1 and low range of AP3.
484         2. Wake up the device.
485         3. Check that device is disconnected form all AP.
486        """
487        self.set_attn_and_validate_connection(
488            self.atten_val["Back_from_blacklist"],
489            self.reference_networks[0]["2g"]['bssid'])
490
491    """ Tests End """
492