blob: 8926409eaa5141260bdb1033fd65571cb550e235 [file] [log] [blame]
Bindu Mahadevb270aa22018-08-27 13:34:58 -07001#!/usr/bin/env python3.4
2#
3# Copyright 2018 - 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
Bindu Mahadev7d8c17e2018-11-16 23:32:57 -080017import re
Bindu Mahadev28138142018-09-17 15:34:07 -070018import sys
Bindu Mahadev0ea5b0a2019-01-04 17:01:33 -080019import random
Bindu Mahadevb270aa22018-08-27 13:34:58 -070020import time
21
22import acts.controllers.packet_capture as packet_capture
Bindu Mahadev6b946792018-09-11 16:26:00 -070023import acts.signals as signals
Bindu Mahadevb270aa22018-08-27 13:34:58 -070024import acts.test_utils.wifi.rpm_controller_utils as rutils
Bindu Mahadev28138142018-09-17 15:34:07 -070025import acts.test_utils.wifi.wifi_datastore_utils as dutils
26import acts.test_utils.wifi.wifi_test_utils as wutils
Bindu Mahadevb270aa22018-08-27 13:34:58 -070027
28from acts import asserts
Bindu Mahadev28138142018-09-17 15:34:07 -070029from acts.base_test import BaseTestClass
Bindu Mahadevb270aa22018-08-27 13:34:58 -070030from acts.controllers.ap_lib import hostapd_constants
31from acts.test_decorators import test_tracker_info
32from acts.test_utils.wifi.WifiBaseTest import WifiBaseTest
33
34WifiEnums = wutils.WifiEnums
35
36WAIT_BEFORE_CONNECTION = 1
37SINGLE_BAND = 1
38DUAL_BAND = 2
39
Bindu Mahadev02dd5ac2018-11-05 12:40:03 -080040TIMEOUT = 60
Bindu Mahadev0ea5b0a2019-01-04 17:01:33 -080041TEST = 'test_'
Bindu Mahadevb270aa22018-08-27 13:34:58 -070042PING_ADDR = 'www.google.com'
43
David Sue7db8922019-03-28 12:36:14 -070044NUM_LINK_PROBES = 3
45PROBE_DELAY_SEC = 1
46
Bindu Mahadev28138142018-09-17 15:34:07 -070047
Bindu Mahadevb270aa22018-08-27 13:34:58 -070048class WifiChaosTest(WifiBaseTest):
49 """ Tests for wifi IOT
50
51 Test Bed Requirement:
52 * One Android device
53 * Wi-Fi IOT networks visible to the device
54 """
55
Bindu Mahadev28138142018-09-17 15:34:07 -070056 def __init__(self, configs):
57 BaseTestClass.__init__(self, configs)
58 self.generate_interop_tests()
59
Bindu Mahadev0ea5b0a2019-01-04 17:01:33 -080060 def randomize_testcases(self):
61 """Randomize the list of hosts and build a random order of tests,
62 based on SSIDs, keeping all the relevant bands of an AP together.
63
64 """
65 temp_tests = list()
66 hosts = self.user_params['interop_host']
67
68 random.shuffle(hosts)
69
70 for host in hosts:
71 ssid_2g = None
72 ssid_5g = None
73 info = dutils.show_device(host)
74
75 # Based on the information in datastore, add to test list if
76 # AP has 2G band.
77 if 'ssid_2g' in info:
78 ssid_2g = info['ssid_2g']
79 temp_tests.append(TEST + ssid_2g)
80
81 # Based on the information in datastore, add to test list if
82 # AP has 5G band.
83 if 'ssid_5g' in info:
84 ssid_5g = info['ssid_5g']
85 temp_tests.append(TEST + ssid_5g)
86
87 self.tests = temp_tests
88
Bindu Mahadev28138142018-09-17 15:34:07 -070089 def generate_interop_testcase(self, base_test, testcase_name, ssid_dict):
90 """Generates a single test case from the given data.
91
92 Args:
93 base_test: The base test case function to run.
94 testcase_name: The name of the test case.
95 ssid_dict: The information about the network under test.
96 """
97 ssid = testcase_name
98 test_tracker_uuid = ssid_dict[testcase_name]['uuid']
99 hostname = ssid_dict[testcase_name]['host']
100 if not testcase_name.startswith('test_'):
101 testcase_name = 'test_%s' % testcase_name
102 test_case = test_tracker_info(uuid=test_tracker_uuid)(
103 lambda: base_test(ssid, hostname))
104 setattr(self, testcase_name, test_case)
105 self.tests.append(testcase_name)
106
107 def generate_interop_tests(self):
108 for ssid_dict in self.user_params['interop_ssid']:
109 testcase_name = list(ssid_dict)[0]
110 self.generate_interop_testcase(self.interop_base_test,
111 testcase_name, ssid_dict)
Bindu Mahadev0ea5b0a2019-01-04 17:01:33 -0800112 self.randomize_testcases()
Bindu Mahadev28138142018-09-17 15:34:07 -0700113
Bindu Mahadevb270aa22018-08-27 13:34:58 -0700114 def setup_class(self):
115 self.dut = self.android_devices[0]
Bindu Mahadev384833d2019-01-11 16:11:26 -0800116 self.admin = 'admin' + str(random.randint(1000001, 12345678))
Bindu Mahadevb270aa22018-08-27 13:34:58 -0700117 wutils.wifi_test_device_init(self.dut)
Bindu Mahadev97ab1812018-10-02 16:33:36 -0700118 # Set country code explicitly to "US".
119 self.dut.droid.wifiSetCountryCode(wutils.WifiEnums.CountryCode.US)
Bindu Mahadevb270aa22018-08-27 13:34:58 -0700120
Bindu Mahadevb270aa22018-08-27 13:34:58 -0700121 asserts.assert_true(
Bindu Mahadev28138142018-09-17 15:34:07 -0700122 self.lock_pcap(),
123 "Could not lock a Packet Capture. Aborting Interop test.")
Bindu Mahadevb270aa22018-08-27 13:34:58 -0700124
125 wutils.wifi_toggle_state(self.dut, True)
126
Bindu Mahadev28138142018-09-17 15:34:07 -0700127 def lock_pcap(self):
128 """Lock a Packet Capturere to use for the test."""
129
130 # Get list of devices from the datastore.
131 locked_pcap = False
132 devices = dutils.get_devices()
133
134 for device in devices:
135
136 device_name = device['hostname']
137 device_type = device['ap_label']
Bindu Mahadev0ea5b0a2019-01-04 17:01:33 -0800138 if device_type == 'PCAP' and not device['lock_status']:
Bindu Mahadev384833d2019-01-11 16:11:26 -0800139 if dutils.lock_device(device_name, self.admin):
Bindu Mahadev0ea5b0a2019-01-04 17:01:33 -0800140 self.pcap_host = device_name
141 host = device['ip_address']
142 self.log.info("Locked Packet Capture device: %s" % device_name)
143 locked_pcap = True
144 break
145 else:
146 self.log.warning("Failed to lock %s PCAP." % device_name)
Bindu Mahadev28138142018-09-17 15:34:07 -0700147
148 if not locked_pcap:
149 return False
150
151 pcap_config = {'ssh_config':{'user':'root'} }
152 pcap_config['ssh_config']['host'] = host
153
154 self.pcap = packet_capture.PacketCapture(pcap_config)
155 return True
156
Bindu Mahadevb270aa22018-08-27 13:34:58 -0700157 def setup_test(self):
158 self.dut.droid.wakeLockAcquireBright()
159 self.dut.droid.wakeUpNow()
160
Bindu Mahadev76551c12018-12-13 19:42:14 +0000161 def on_pass(self, test_name, begin_time):
xianyuanjia0431ba32018-12-14 09:56:42 -0800162 wutils.stop_pcap(self.pcap, self.pcap_procs, True)
Bindu Mahadev76551c12018-12-13 19:42:14 +0000163
Bindu Mahadev7d8c17e2018-11-16 23:32:57 -0800164 def on_fail(self, test_name, begin_time):
Bindu Mahadev13634dd2019-03-28 14:24:12 -0700165 # Sleep to ensure all failed packets are captured.
166 time.sleep(5)
xianyuanjia0431ba32018-12-14 09:56:42 -0800167 wutils.stop_pcap(self.pcap, self.pcap_procs, False)
Bindu Mahadev170a50b2018-11-27 15:20:31 -0800168 self.dut.take_bug_report(test_name, begin_time)
169 self.dut.cat_adb_log(test_name, begin_time)
Bindu Mahadev7d8c17e2018-11-16 23:32:57 -0800170
Bindu Mahadevb270aa22018-08-27 13:34:58 -0700171 def teardown_test(self):
172 self.dut.droid.wakeLockRelease()
173 self.dut.droid.goToSleepNow()
Bindu Mahadev0ea5b0a2019-01-04 17:01:33 -0800174
175 def teardown_class(self):
176 # Unlock the PCAP.
177 if not dutils.unlock_device(self.pcap_host):
178 self.log.warning("Failed to unlock %s PCAP. Check in datastore.")
Bindu Mahadevb270aa22018-08-27 13:34:58 -0700179
Bindu Mahadevb270aa22018-08-27 13:34:58 -0700180
181 """Helper Functions"""
182
183 def scan_and_connect_by_id(self, network, net_id):
184 """Scan for network and connect using network id.
185
186 Args:
187 net_id: Integer specifying the network id of the network.
188
189 """
190 ssid = network[WifiEnums.SSID_KEY]
191 wutils.start_wifi_connection_scan_and_ensure_network_found(self.dut,
Bindu Mahadev28138142018-09-17 15:34:07 -0700192 ssid)
Bindu Mahadevb270aa22018-08-27 13:34:58 -0700193 wutils.wifi_connect_by_id(self.dut, net_id)
194
195 def run_ping(self, sec):
196 """Run ping for given number of seconds.
197
198 Args:
199 sec: Time in seconds to run teh ping traffic.
200
201 """
202 self.log.info("Running ping for %d seconds" % sec)
203 result = self.dut.adb.shell("ping -w %d %s" % (sec, PING_ADDR),
Bindu Mahadev28138142018-09-17 15:34:07 -0700204 timeout=sec + 1)
Bindu Mahadevb270aa22018-08-27 13:34:58 -0700205 self.log.debug("Ping Result = %s" % result)
206 if "100% packet loss" in result:
207 raise signals.TestFailure("100% packet loss during ping")
208
David Sue7db8922019-03-28 12:36:14 -0700209 def send_link_probes(self, network):
210 """
211 Send link probes, and verify that the device and AP did not crash.
212 Also verify that at least one link probe succeeded.
213
214 Steps:
215 1. Send a few link probes.
216 2. Verify that at least one link probe succeeded.
217 3. Ensure that the device and AP did not crash (by checking that the
218 device remains connected to the expected network).
219 """
220 results = wutils.send_link_probes(
221 self.dut, NUM_LINK_PROBES, PROBE_DELAY_SEC)
222
223 asserts.assert_true(any(result.is_success for result in results),
224 "Expect at least 1 probe success: " + str(results))
225
226 wifi_info = self.dut.droid.wifiGetConnectionInfo()
227 expected = network[WifiEnums.SSID_KEY]
228 actual = wifi_info[WifiEnums.SSID_KEY]
229 asserts.assert_equal(
230 expected, actual,
231 "Device did not remain connected after sending link probes!")
232
Bindu Mahadev02dd5ac2018-11-05 12:40:03 -0800233 def unlock_and_turn_off_ap(self, hostname, rpm_port, rpm_ip):
234 """UNlock the AP in datastore and turn off the AP.
235
236 Args:
237 hostname: Hostname of the AP.
238 rpm_port: Port number on the RPM for the AP.
239 rpm_ip: RPM's IP address.
240
241 """
242 # Un-Lock AP in datastore.
243 self.log.debug("Un-lock AP in datastore")
244 if not dutils.unlock_device(hostname):
245 self.log.warning("Failed to unlock %s AP. Check AP in datastore.")
246 # Turn OFF AP from the RPM port.
247 rutils.turn_off_ap(rpm_port, rpm_ip)
248
249 def run_connect_disconnect(self, network, hostname, rpm_port, rpm_ip,
250 release_ap):
Bindu Mahadev28138142018-09-17 15:34:07 -0700251 """Run connect/disconnect to a given network in loop.
Bindu Mahadevb270aa22018-08-27 13:34:58 -0700252
Bindu Mahadev28138142018-09-17 15:34:07 -0700253 Args:
Bindu Mahadev02dd5ac2018-11-05 12:40:03 -0800254 network: Dict, network information.
255 hostname: Hostanme of the AP to connect to.
256 rpm_port: Port number on the RPM for the AP.
257 rpm_ip: Port number on the RPM for the AP.
258 release_ap: Flag to determine if we should turn off the AP yet.
Bindu Mahadevb270aa22018-08-27 13:34:58 -0700259
Bindu Mahadev28138142018-09-17 15:34:07 -0700260 Raises: TestFailure if the network connection fails.
Bindu Mahadevb270aa22018-08-27 13:34:58 -0700261
262 """
Bindu Mahadev9bc3d972018-12-13 14:40:54 -0800263 for attempt in range(5):
Bindu Mahadev28138142018-09-17 15:34:07 -0700264 try:
265 begin_time = time.time()
266 ssid = network[WifiEnums.SSID_KEY]
267 net_id = self.dut.droid.wifiAddNetwork(network)
268 asserts.assert_true(net_id != -1, "Add network %s failed" % network)
269 self.log.info("Connecting to %s" % ssid)
270 self.scan_and_connect_by_id(network, net_id)
Bindu Mahadev0ea5b0a2019-01-04 17:01:33 -0800271 self.run_ping(10)
David Sue7db8922019-03-28 12:36:14 -0700272 self.send_link_probes(network)
Bindu Mahadev28138142018-09-17 15:34:07 -0700273 wutils.wifi_forget_network(self.dut, ssid)
274 time.sleep(WAIT_BEFORE_CONNECTION)
275 except:
276 self.log.error("Connection to %s network failed on the %d "
277 "attempt." % (ssid, attempt))
Bindu Mahadevbe757572018-09-25 10:23:51 -0700278 # TODO:(bmahadev) Uncomment after scan issue is fixed.
279 # self.dut.take_bug_report(ssid, begin_time)
280 # self.dut.cat_adb_log(ssid, begin_time)
Bindu Mahadev02dd5ac2018-11-05 12:40:03 -0800281 if release_ap:
282 self.unlock_and_turn_off_ap(hostname, rpm_port, rpm_ip)
Bindu Mahadev28138142018-09-17 15:34:07 -0700283 raise signals.TestFailure("Failed to connect to %s" % ssid)
Bindu Mahadevb270aa22018-08-27 13:34:58 -0700284
Bindu Mahadev7d8c17e2018-11-16 23:32:57 -0800285 def get_band_and_chan(self, ssid):
286 """Get the band and channel information from SSID.
287
288 Args:
289 ssid: SSID of the network.
290
291 """
292 ssid_info = ssid.split('_')
293 self.band = ssid_info[-1]
294 for item in ssid_info:
Bindu Mahadev044cabd2018-11-26 14:56:57 -0800295 # Skip over the router model part.
296 if 'ch' in item and item != ssid_info[0]:
Bindu Mahadev7d8c17e2018-11-16 23:32:57 -0800297 self.chan = re.search(r'(\d+)',item).group(0)
298 return
299 raise signals.TestFailure("Channel information not found in SSID.")
300
Bindu Mahadev28138142018-09-17 15:34:07 -0700301 def interop_base_test(self, ssid, hostname):
302 """Base test for all the connect-disconnect interop tests.
Bindu Mahadevb270aa22018-08-27 13:34:58 -0700303
Bindu Mahadev28138142018-09-17 15:34:07 -0700304 Args:
305 ssid: string, SSID of the network to connect to.
306 hostname: string, hostname of the AP.
Bindu Mahadevb270aa22018-08-27 13:34:58 -0700307
Bindu Mahadev28138142018-09-17 15:34:07 -0700308 Steps:
309 1. Lock AP in datstore.
310 2. Turn on AP on the rpm switch.
311 3. Run connect-disconnect in loop.
312 4. Turn off AP on the rpm switch.
313 5. Unlock AP in datastore.
Bindu Mahadevb270aa22018-08-27 13:34:58 -0700314
Bindu Mahadev28138142018-09-17 15:34:07 -0700315 """
316 network = {}
317 network['password'] = 'password'
318 network['SSID'] = ssid
Bindu Mahadev02dd5ac2018-11-05 12:40:03 -0800319 release_ap = False
Bindu Mahadev28138142018-09-17 15:34:07 -0700320 wutils.reset_wifi(self.dut)
Bindu Mahadevb270aa22018-08-27 13:34:58 -0700321
Bindu Mahadev28138142018-09-17 15:34:07 -0700322 # Lock AP in datastore.
323 self.log.info("Lock AP in datastore")
Bindu Mahadev0ea5b0a2019-01-04 17:01:33 -0800324
325 ap_info = dutils.show_device(hostname)
326
Bindu Mahadev384833d2019-01-11 16:11:26 -0800327 # If AP is locked by a different test admin, then we skip.
328 if ap_info['lock_status'] and ap_info['locked_by'] != self.admin:
Bindu Mahadev0ea5b0a2019-01-04 17:01:33 -0800329 raise signals.TestSkip("AP %s is locked, skipping test" % hostname)
330
Bindu Mahadev384833d2019-01-11 16:11:26 -0800331 if not dutils.lock_device(hostname, self.admin):
Bindu Mahadev28138142018-09-17 15:34:07 -0700332 self.log.warning("Failed to lock %s AP. Unlock AP in datastore"
333 " and try again.")
334 raise signals.TestFailure("Failed to lock AP")
Bindu Mahadevb270aa22018-08-27 13:34:58 -0700335
Bindu Mahadev28138142018-09-17 15:34:07 -0700336 band = SINGLE_BAND
337 if ('ssid_2g' in ap_info) and ('ssid_5g' in ap_info):
338 band = DUAL_BAND
Bindu Mahadev02dd5ac2018-11-05 12:40:03 -0800339 if (band == SINGLE_BAND) or (
340 band == DUAL_BAND and '5G' in ssid):
341 release_ap = True
Bindu Mahadevb270aa22018-08-27 13:34:58 -0700342
Bindu Mahadev28138142018-09-17 15:34:07 -0700343 # Get AP RPM attributes and Turn ON AP.
344 rpm_ip = ap_info['rpm_ip']
345 rpm_port = ap_info['rpm_port']
Bindu Mahadevb270aa22018-08-27 13:34:58 -0700346
Bindu Mahadev28138142018-09-17 15:34:07 -0700347 rutils.turn_on_ap(self.pcap, ssid, rpm_port, rpm_ip=rpm_ip)
348 self.log.info("Finished turning ON AP.")
Bindu Mahadev02dd5ac2018-11-05 12:40:03 -0800349 # Experimental. Some APs take upto a min to come online.
Bindu Mahadevd9c60d72019-03-06 20:42:15 +0000350 time.sleep(60)
Bindu Mahadev6b946792018-09-11 16:26:00 -0700351
Bindu Mahadev7d8c17e2018-11-16 23:32:57 -0800352 self.get_band_and_chan(ssid)
353 self.pcap.configure_monitor_mode(self.band, self.chan)
xianyuanjia0431ba32018-12-14 09:56:42 -0800354 self.pcap_procs = wutils.start_pcap(
Bindu Mahadev76551c12018-12-13 19:42:14 +0000355 self.pcap, self.band.lower(), self.log_path, self.test_name)
Bindu Mahadev7d8c17e2018-11-16 23:32:57 -0800356 self.run_connect_disconnect(network, hostname, rpm_port, rpm_ip,
357 release_ap)
Bindu Mahadevb270aa22018-08-27 13:34:58 -0700358
Bindu Mahadev28138142018-09-17 15:34:07 -0700359 # Un-lock only if it's a single band AP or we are running the last band.
Bindu Mahadev02dd5ac2018-11-05 12:40:03 -0800360 if release_ap:
361 self.unlock_and_turn_off_ap(hostname, rpm_port, rpm_ip)