Home | History | Annotate | Download | only in functional
      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