1#!/usr/bin/env python3 2# 3# Copyright (C) 2018 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); you may not 6# use this file except in compliance with the License. You may obtain a copy of 7# 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, WITHOUT 13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14# License for the specific language governing permissions and limitations under 15# the License. 16""" 17Script for testing various download stress scenarios. 18 19""" 20import os 21import threading 22import uuid 23 24from acts.base_test import BaseTestClass 25from acts import signals 26from acts.controllers.ap_lib import hostapd_constants 27from acts.test_utils.abstract_devices.utils_lib.wlan_utils import setup_ap_and_associate 28from acts.test_utils.abstract_devices.wlan_device import create_wlan_device 29from acts.test_utils.fuchsia import utils 30from acts.test_utils.tel.tel_test_utils import setup_droid_properties 31from acts.utils import rand_ascii_str 32 33 34class DownloadStressTest(BaseTestClass): 35 # Default number of test iterations here. 36 # Override using parameter in config file. 37 # Eg: "download_stress_test_iterations": "10" 38 num_of_iterations = 3 39 40 # Timeout for download thread in seconds 41 download_timeout_s = 60 * 5 42 43 # Download urls 44 url_20MB = 'http://ipv4.download.thinkbroadband.com/20MB.zip' 45 url_40MB = 'http://ipv4.download.thinkbroadband.com/40MB.zip' 46 url_60MB = 'http://ipv4.download.thinkbroadband.com/60MB.zip' 47 url_512MB = 'http://ipv4.download.thinkbroadband.com/512MB.zip' 48 49 # Constants used in test_one_large_multiple_small_downloads 50 download_small_url = url_20MB 51 download_large_url = url_512MB 52 num_of_small_downloads = 5 53 download_threads_result = [] 54 55 def setup_class(self): 56 super().setup_class() 57 self.ssid = rand_ascii_str(10) 58 self.fd = self.fuchsia_devices[0] 59 self.wlan_device = create_wlan_device(self.fd) 60 self.ap = self.access_points[0] 61 self.num_of_iterations = int( 62 self.user_params.get("download_stress_test_iterations", 63 self.num_of_iterations)) 64 65 setup_ap_and_associate( 66 access_point=self.ap, 67 client=self.wlan_device, 68 profile_name='whirlwind', 69 channel=hostapd_constants.AP_DEFAULT_CHANNEL_2G, 70 ssid=self.ssid) 71 72 def teardown_test(self): 73 self.download_threads_result.clear() 74 self.wlan_device.disconnect() 75 self.wlan_device.reset_wifi() 76 self.ap.stop_all_aps() 77 78 def test_download_small(self): 79 self.log.info("Downloading small file") 80 return self.download_file(self.url_20MB) 81 82 def test_download_large(self): 83 return self.download_file(self.url_512MB) 84 85 def test_continuous_download(self): 86 for x in range(0, self.num_of_iterations): 87 if not self.download_file(self.url_512MB): 88 return False 89 return True 90 91 def download_file(self, url): 92 self.log.info("Start downloading: %s" % url) 93 return utils.http_file_download_by_curl( 94 self.fd, 95 url, 96 additional_args='--max-time %d --silent' % self.download_timeout_s) 97 98 def download_thread(self, url): 99 download_status = self.download_file(url) 100 if download_status: 101 self.log.info("Success downloading: %s" % url) 102 else: 103 self.log.info("Failure downloading: %s" % url) 104 105 self.download_threads_result.append(download_status) 106 return download_status 107 108 def test_multi_downloads(self): 109 download_urls = [self.url_20MB, self.url_40MB, self.url_60MB] 110 download_threads = [] 111 112 try: 113 # Start multiple downloads at the same time 114 for index, url in enumerate(download_urls): 115 self.log.info('Create and start thread %d.' % index) 116 t = threading.Thread(target=self.download_thread, args=(url, )) 117 download_threads.append(t) 118 t.start() 119 120 # Wait for all threads to complete or timeout 121 for t in download_threads: 122 t.join(self.download_timeout_s) 123 124 finally: 125 is_alive = False 126 127 for index, t in enumerate(download_threads): 128 if t.isAlive(): 129 t = None 130 is_alive = True 131 132 if is_alive: 133 raise signals.TestFailure('Thread %d timedout' % index) 134 135 for index in range(0, len(self.download_threads_result)): 136 if not self.download_threads_result[index]: 137 self.log.info("Download failed for %d" % index) 138 raise signals.TestFailure( 139 'Thread %d failed to download' % index) 140 return False 141 142 return True 143 144 def test_one_large_multiple_small_downloads(self): 145 for index in range(self.num_of_iterations): 146 download_threads = [] 147 try: 148 large_thread = threading.Thread( 149 target=self.download_thread, 150 args=(self.download_large_url, )) 151 download_threads.append(large_thread) 152 large_thread.start() 153 154 for i in range(self.num_of_small_downloads): 155 # Start small file download 156 t = threading.Thread( 157 target=self.download_thread, 158 args=(self.download_small_url, )) 159 download_threads.append(t) 160 t.start() 161 # Wait for thread to exit before starting the next iteration 162 t.join(self.download_timeout_s) 163 164 # Wait for the large file download thread to complete 165 large_thread.join(self.download_timeout_s) 166 167 finally: 168 is_alive = False 169 170 for index, t in enumerate(download_threads): 171 if t.isAlive(): 172 t = None 173 is_alive = True 174 175 if is_alive: 176 raise signals.TestFailure('Thread %d timedout' % index) 177 178 for index in range(0, len(self.download_threads_result)): 179 if not self.download_threads_result[index]: 180 self.log.info("Download failed for %d" % index) 181 raise signals.TestFailure( 182 'Thread %d failed to download' % index) 183 return False 184 185 # Clear results before looping again 186 self.download_threads_result.clear() 187 188 return True 189