1#!/usr/bin/env python3 2# 3# Copyright 2020 - 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 csv 18import json 19import os 20import time 21import acts_contrib.test_utils.wifi.wifi_test_utils as wutils 22from acts import signals 23from acts.test_decorators import test_tracker_info 24from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest 25from acts_contrib.test_utils.wifi import pdu_controller_utils 26 27WifiEnums = wutils.WifiEnums 28WAIT_BETWEEN_ACTIONS = 5 29 30class WifiIOTConnectionTest(WifiBaseTest): 31 """ Tests for wifi IOT Connection 32 33 Test Bed Requirement: 34 * One Android device 35 * Wi-Fi IOT networks visible to the device 36 """ 37 38 def __init__(self, controllers): 39 WifiBaseTest.__init__(self, controllers) 40 self.generate_test_list() 41 42 def setup_class(self): 43 self.dut = self.android_devices[0] 44 self.pdu = pdu_controller_utils.create(self.user_params['Pdu'])[0] 45 46 if hasattr(self, 'packet_capture'): 47 self.packet_capture = self.packet_capture[0] 48 49 wutils.wifi_test_device_init(self.dut) 50 51 self.csv_write(["Project", "TimeStamp", "Build_ID", "Test_Name", 52 "Host", "RSSI", "Link_speed", "freq", "#iteration", 53 "#Pass"], ) 54 55 req_params = ['iot_password', 'pdu_wait_time', 56 'iot_ssid', 'Pdu', 'iot_connection_iteration'] 57 self.unpack_userparams( 58 req_param_names=req_params) 59 60 def setup_test(self): 61 self.dut.droid.wakeLockAcquireBright() 62 self.dut.droid.wakeUpNow() 63 wutils.reset_wifi(self.dut) 64 65 def teardown_test(self): 66 self.dut.droid.wakeLockRelease() 67 self.dut.droid.goToSleepNow() 68 if hasattr(self, 'packet_capture'): 69 wutils.stop_pcap(self.packet_capture, self.pcap_procs, False) 70 71 def on_fail(self, test_name, begin_time): 72 self.dut.take_bug_report(test_name, begin_time) 73 self.dut.cat_adb_log(test_name, begin_time) 74 75 def csv_write(self, data): 76 """Output .CSV file as a result. 77 78 Args: 79 data: a dict containing: 80 'project', 'TimeStamp', 'test_name', 'test_name', 81 'host', 'rssi', 'link_speed', 'freq', '#Iteration', '#Pass' 82 """ 83 time_str = time.strftime("%Y-%m-%d") 84 file_name_format = "wifi_iot_connection_" + time_str + ".csv" 85 file_name = os.path.join(self.log_path, file_name_format) 86 with open(file_name, "a", newline="") as csv_file: 87 csv_writer = csv.writer(csv_file, delimiter=',') 88 csv_writer.writerow(data) 89 90 def get_wifi_info(self): 91 """Get current connected WiFi AP's info. 92 93 Returns: 94 rssi: Wi-Fi rssi 95 link_speed: Wi-Fi link speed 96 freq: Wi-Fi freq 97 """ 98 freq = "NA" 99 link_speed = "NA" 100 rssi = "NA" 101 102 try: 103 out = self.dut.adb.shell("iw wlan0 link") 104 if out: 105 for line in out.split("\n"): 106 if "freq:" in line: 107 freq = line.split()[1] 108 elif "signal" in line: 109 rssi = line.split()[1] 110 elif "bitrate" in line: 111 link_speed = line.split()[2] 112 except AttributeError as e: 113 self.log.debug("No wifi info, check Wi-Fi connection.", e) 114 finally: 115 return rssi, link_speed, freq 116 117 def getprop(self, property_name): 118 """Get dut's property 119 120 Args: 121 property_name: property name, e.g., "ro.build.product" 122 Return: 123 property 124 """ 125 return self.dut.adb.getprop(property_name) 126 127 def generate_test_list(self): 128 """Generates a test list which is sorted by host number.""" 129 sorted_list = sorted( 130 self.user_params["iot_ssid"], key=lambda ssid: ssid["host"]) 131 for test_item in sorted_list: 132 self.init_test_case(self.wifi_iot_connection_test, test_item) 133 134 def init_test_case(self, wifi_iot_connection_test, test_item): 135 """Generates a single test case from the given data. 136 137 Args: 138 wifi_iot_connection_test: The base test case function to run. 139 test_item: test case required info, include: 140 "ssid", "uuid", "host", "band", "channel" 141 """ 142 test_name = test_item["ssid"] 143 test_tracker_uuid = test_item["uuid"] 144 if not test_name.startswith("test_"): 145 test_name = "test_{}".format(test_name) 146 test_case = test_tracker_info(uuid=test_tracker_uuid)( 147 lambda: wifi_iot_connection_test(test_item, 148 self.user_params["iot_password"])) 149 setattr(self, test_name, test_case) 150 self.tests.append(test_name) 151 152 def pdu_status_check(self): 153 """ Check pdu status 154 if pdu's currently ON outlet != next test case's host number, 155 switch ON outlet to the host number. 156 for example: pdu's outlet 3 is on, next test case host number is 4, 157 turn off pdu outlet 3 and turn on outlet 4. 158 """ 159 _, self.pdu_status = self.pdu.get_status() 160 self.log.info("Current host of the pdu : {}".format(self.pdu_status)) 161 self.log.info("Next host of the test case : {}".format(self.host)) 162 if str(self.host) != self.pdu_status: 163 self.pdu.off_all() 164 self.log.info("Switch PDU to {}".format(self.host)) 165 self.pdu.turn_on_outlets(str(self.host)) 166 self.log.info("Wait {} secs to bring up the APs" 167 .format(self.user_params["pdu_wait_time"])) 168 time.sleep(self.user_params["pdu_wait_time"]) 169 170 def start_packet_capture(self, band, channel): 171 """Configure wireless packet capture on pre-defined channels. 172 173 Args: 174 band: '2G' or '5G'. pre-defined in config file. 175 channel: Wi-fi Channel, pre-defined in the config file. 176 """ 177 self.log.info("Capturing packets from Channel: {}".format(channel)) 178 result = self.packet_capture.configure_monitor_mode(band, channel) 179 if not result: 180 self.dut.log.error("Failed to configure channel " 181 "for {} band".format(band)) 182 self.pcap_procs = wutils.start_pcap( 183 self.packet_capture, band, self.current_test_name) 184 time.sleep(3) 185 186 def ping_public_gateway_ip(self): 187 """Ping 8.8.8.8""" 188 try: 189 ping_result = self.dut.adb.shell('ping -w 5 8.8.8.8') 190 if '0%' in ping_result: 191 self.dut.log.info('Ping success') 192 return True 193 except: 194 self.dut.log.error('Faild to ping public gateway 8.8.8.8') 195 return False 196 197 def connect_to_network_and_ping(self, network): 198 ssid = network[WifiEnums.SSID_KEY] 199 connection_pass = 0 200 for i in range(self.user_params['iot_connection_iteration']): 201 self.dut.log.info('Connection iteration : {}'.format(i + 1)) 202 try: 203 wutils.connect_to_wifi_network(self.dut, network, 204 num_of_connect_tries=1, 205 check_connectivity=False) 206 time.sleep(WAIT_BETWEEN_ACTIONS) 207 self.rssi, self.link_speed, self.freq = self.get_wifi_info() 208 time.sleep(WAIT_BETWEEN_ACTIONS) 209 if self.ping_public_gateway_ip(): 210 connection_pass += 1 211 wutils.wifi_forget_network(self.dut, ssid) 212 self.dut.log.info("connection_pass: {}" 213 .format(connection_pass)) 214 time.sleep(WAIT_BETWEEN_ACTIONS) 215 except: 216 self.dut.log.error("connection_fail") 217 218 # Create a dictionary to store data in a json file. 219 connection_result = {} 220 connection_result["project"] = self.getprop("ro.build.product") 221 connection_result["TimeStamp"] = time.strftime("%Y-%m-%d %H:%M:%S", 222 time.localtime()) 223 connection_result["Build ID"] = self.getprop("ro.build.id") 224 connection_result["test_name"] = self.current_test_name 225 connection_result["host"] = self.host 226 connection_result['rssi'] = self.rssi 227 connection_result['link_speed'] = self.link_speed 228 connection_result['freq'] = self.freq 229 connection_result['#Iteration'] = self.user_params[ 230 'iot_connection_iteration'] 231 connection_result['#Pass'] = connection_pass 232 233 # Create a json file for each test case. 234 results_file_path = os.path.join(self.log_path, "{}.json".format( 235 self.current_test_name)) 236 237 with open(results_file_path, 'w') as results_file: 238 json.dump(connection_result, results_file, indent=4) 239 240 data = (self.getprop("ro.build.product"), 241 time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), 242 self.getprop("ro.build.id"), 243 connection_result["test_name"], 244 connection_result["host"], 245 connection_result['rssi'], 246 connection_result['link_speed'], 247 connection_result['freq'], 248 connection_result['#Iteration'], 249 connection_result['#Pass'] 250 ) 251 252 self.csv_write(data) 253 254 self.rssi = "NA" 255 self.link_speed = "NA" 256 self.freq = "NA" 257 258 if connection_pass < self.user_params['iot_connection_iteration']: 259 raise signals.TestFailure("connection failed more than expected") 260 261 def wifi_iot_connection_test(self, test_item, password): 262 """The base test case logic for Wifi IOT generated test cases. 263 264 1. Check pdu outlets is ON as expected. 265 2. Scan SSIDs of 10 Wi-Fi APs. 266 3. Start Packet Capture on pre-defined channel. 267 3. Connect to the AP and ping Gateway 8.8.8.8 for 5 times. 268 269 Args: 270 test_item: Test info include: 271 'ssid', 'host', 'uuid', 'band', 'channel'. 272 password: pwd for login to the access point. 273 """ 274 network = {'SSID': test_item["ssid"], 'password': password} 275 self.host = test_item["host"] 276 self.pdu_status_check() 277 278 # Capturing wireless packets before DUT connect to Wi-Fi network. 279 self.band = test_item["band"] 280 self.channel = test_item["channel"] 281 if hasattr(self, 'packet_capture'): 282 self.start_packet_capture(self.band, self.channel) 283 284 # Connect to Wi-Fi network and ping public gateway for 5 times. 285 self.connect_to_network_and_ping(network) 286