1 #!/usr/bin/env python 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 3 # Use of this source code is governed by a BSD-style license that can be 4 # found in the LICENSE file. 5 6 import hashlib 7 import logging 8 import os 9 import time 10 import urllib2 11 12 import pyauto_functional # Must be imported before pyauto 13 import pyauto 14 import pyauto_utils 15 import chromeos_network 16 17 18 MAX_WAIT_TIME_IN_MSEC = 15 * 60 * 1000 19 20 21 class WifiDownloadsTest(chromeos_network.PyNetworkUITest): 22 """TestCase for ChromeOS Wifi Downloads 23 24 This test makes a few assumptions. It needs to have access to the power 25 strip used in pyautolib/chromeos/wifi_downloads.py. It also assumes access 26 to the server 172.22.12.98:8080. If the server is passed a filname in the 27 format <integer>.lf, it will generate a file of size <integer> in KB. In 28 addition the name of the file returned is the md5 checksum of the file. 29 30 In addition the download times are written to a file in 31 /tmp/wifi_download_time.csv. All times are appended to the file if it 32 already exists. 33 """ 34 35 def setUp(self): 36 chromeos_network.PyNetworkUITest.setUp(self) 37 self.InitWifiPowerStrip() 38 # The power strip is a shared resource and if we every crash in the middle 39 # of a test we will be in an unknown state. This returns us to 'all off'. 40 self.TurnOffAllRouters() 41 # Downloading files of a large size, can take a while, bump the timeout 42 self.changer = pyauto.PyUITest.ActionTimeoutChanger(self, 4 * 1000 * 60) 43 self.log_file_path = '/tmp/wifi_download_time.csv' 44 45 def _WriteTimeToFile(self, output_file, router_name, file_size, dl_time): 46 """Write or append a time into a csv file. 47 48 This method will create or append the amount of time a download took for a 49 given filesize and router to a file at the given path. 50 51 The format of the output file is as follows: 52 <router name A>,<file size A>,time,time,time,time,time,time,time,time 53 <router name A>,<file size B>,time,time,time,time,time,time,time,time 54 <router name B>,<file size C>,time,time,time,time,time,time,time,time 55 56 Args: 57 output_file: the complete path of the file to write to 58 file_size: the size of the file, this is the row header 59 dl_time: the amount of time in seconds 60 """ 61 file_data = [] 62 if os.path.exists(output_file): 63 file_handle = open(output_file) 64 lines = file_handle.readlines() 65 file_handle.close() 66 # Convert the file to a full data structure. 67 for line in lines: 68 values = line.strip().split(',') 69 file_data.append(values) 70 for values in file_data: 71 found_existing_time = False 72 if values[0] == router_name and values[1] == file_size: 73 values.append('%2.2f' % dl_time) 74 found_existing_time = True 75 break 76 if not found_existing_time: 77 new_line = [router_name, file_size, ('%2.2f' % dl_time)] 78 file_data.append(new_line) 79 else: 80 file_data = [[router_name, file_size, ('%2.2f' % dl_time)]] 81 # Write the data back out 82 file_handle = open(output_file, 'w') 83 for line in file_data: 84 if len(line) > 2: 85 file_handle.write(','.join(line)) 86 file_handle.write('\n') 87 file_handle.close() 88 89 def _Md5Checksum(self, file_path): 90 """Returns the md5 checksum of a file at a given path. 91 92 Args: 93 file_path: The complete path of the file to generate the md5 checksum for. 94 """ 95 file_handle = open(file_path, 'rb') 96 m = hashlib.md5() 97 while True: 98 data = file_handle.read(8192) 99 if not data: 100 break 101 m.update(data) 102 file_handle.close() 103 return m.hexdigest() 104 105 def _ConnectToRouterAndVerify(self, router_name): 106 """Generic routine for connecting to a router. 107 108 Args: 109 router_name: The name of the router to connect to. 110 """ 111 router = self.GetRouterConfig(router_name) 112 self.RouterPower(router_name, True) 113 114 self.assertTrue(self.WaitUntilWifiNetworkAvailable(router['ssid']), 115 'Wifi network %s never showed up.' % router['ssid']) 116 117 # Verify connect did not have any errors. 118 error = self.ConnectToWifiRouter(router_name) 119 self.assertFalse(error, 'Failed to connect to wifi network %s. ' 120 'Reason: %s.' % (router['ssid'], error)) 121 122 # Verify the network we connected to. 123 ssid = self.GetConnectedWifi() 124 self.assertEqual(ssid, router['ssid'], 125 'Did not successfully connect to wifi network %s.' % ssid) 126 127 def _DownloadAndVerifyFile(self, download_url): 128 """Downloads a file at a given URL and validates it 129 130 This method downloads a file from a server whose filename matches the md5 131 checksum. Then we manually generate the md5 and check it against the 132 filename. 133 134 Args: 135 download_url: URL of the file to download. 136 137 Returns: 138 The download time in seconds. 139 """ 140 start = time.time() 141 # Make a copy of the download directory now to work around segfault 142 downloads_dir = self.GetDownloadDirectory().value() 143 try: 144 self.DownloadAndWaitForStart(download_url) 145 except AssertionError: 146 # We need to redo this since the external server may not respond the 147 # first time. 148 logging.info('Could not start download. Retrying ...') 149 self.DownloadAndWaitForStart(download_url) 150 # Maximum wait time is set as 15 mins as an 100MB file may take somewhere 151 # between 8-12 mins to download. 152 self.WaitForAllDownloadsToComplete(timeout=MAX_WAIT_TIME_IN_MSEC) 153 end = time.time() 154 logging.info('Download took %2.2f seconds to complete' % (end - start)) 155 downloaded_files = os.listdir(downloads_dir) 156 self.assertEquals(len(downloaded_files), 1, 157 msg='Expected only one file in the Downloads folder. ' 158 'but got this instead: %s' % ', '.join(downloaded_files)) 159 filename = os.path.splitext(downloaded_files[0])[0] 160 file_path = os.path.join(self.GetDownloadDirectory().value(), 161 downloaded_files[0]) 162 md5_sum = self._Md5Checksum(file_path) 163 md5_url = download_url[:-4] + '.md5' # replacing .slf with .md5 164 md5_file = urllib2.urlopen(md5_url).readlines()[0] 165 self.assertTrue(md5_file.rstrip().endswith(md5_sum.encode()), 166 msg='Unexpected checksum. The download is incomplete.') 167 return end - start 168 169 def testDownload1MBFile(self): 170 """Test downloading a 1MB file from a wireless router.""" 171 download_url = 'http://172.22.12.98:80/downloads/1M.slf' 172 router_name = 'Nfiniti' 173 self._ConnectToRouterAndVerify(router_name) 174 download_time = self._DownloadAndVerifyFile(download_url) 175 self._WriteTimeToFile(self.log_file_path, router_name, '1MB', 176 download_time) 177 self.DisconnectFromWifiNetwork() 178 179 def testDownload10MBFile(self): 180 """Test downloading a 10MB file from a wireless router.""" 181 download_url = 'http://172.22.12.98:80/downloads/10M.slf' 182 router_name = 'Linksys_WRT54G2' 183 self._ConnectToRouterAndVerify(router_name) 184 download_time = self._DownloadAndVerifyFile(download_url) 185 self._WriteTimeToFile(self.log_file_path, router_name, '10MB', 186 download_time) 187 self.DisconnectFromWifiNetwork() 188 189 def testDownload100MBFile(self): 190 """Test downloading a 100MB file from a wireless router.""" 191 download_url = 'http://172.22.12.98:80/downloads/100M.slf' 192 router_name = 'Trendnet_639gr_4' 193 self._ConnectToRouterAndVerify(router_name) 194 download_time = self._DownloadAndVerifyFile(download_url) 195 self._WriteTimeToFile(self.log_file_path, router_name, '100MB', 196 download_time) 197 self.DisconnectFromWifiNetwork() 198 199 200 if __name__ == '__main__': 201 pyauto_functional.Main() 202