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.access_point import setup_ap 27from acts.controllers.ap_lib import hostapd_constants 28from acts_contrib.test_utils.abstract_devices.wlan_device import create_wlan_device 29from acts_contrib.test_utils.fuchsia import utils 30from acts_contrib.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(access_point=self.ap, 66 profile_name='whirlwind', 67 channel=hostapd_constants.AP_DEFAULT_CHANNEL_2G, 68 ssid=self.ssid) 69 self.wlan_device.associate(self.ssid) 70 71 def teardown_test(self): 72 self.download_threads_result.clear() 73 self.wlan_device.disconnect() 74 self.wlan_device.reset_wifi() 75 self.ap.stop_all_aps() 76 77 def test_download_small(self): 78 self.log.info("Downloading small file") 79 return self.download_file(self.url_20MB) 80 81 def test_download_large(self): 82 return self.download_file(self.url_512MB) 83 84 def test_continuous_download(self): 85 for x in range(0, self.num_of_iterations): 86 if not self.download_file(self.url_512MB): 87 return False 88 return True 89 90 def download_file(self, url): 91 self.log.info("Start downloading: %s" % url) 92 return utils.http_file_download_by_curl( 93 self.fd, 94 url, 95 additional_args='--max-time %d --silent' % self.download_timeout_s) 96 97 def download_thread(self, url): 98 download_status = self.download_file(url) 99 if download_status: 100 self.log.info("Success downloading: %s" % url) 101 else: 102 self.log.info("Failure downloading: %s" % url) 103 104 self.download_threads_result.append(download_status) 105 return download_status 106 107 def test_multi_downloads(self): 108 download_urls = [self.url_20MB, self.url_40MB, self.url_60MB] 109 download_threads = [] 110 111 try: 112 # Start multiple downloads at the same time 113 for index, url in enumerate(download_urls): 114 self.log.info('Create and start thread %d.' % index) 115 t = threading.Thread(target=self.download_thread, args=(url, )) 116 download_threads.append(t) 117 t.start() 118 119 # Wait for all threads to complete or timeout 120 for t in download_threads: 121 t.join(self.download_timeout_s) 122 123 finally: 124 is_alive = False 125 126 for index, t in enumerate(download_threads): 127 if t.isAlive(): 128 t = None 129 is_alive = True 130 131 if is_alive: 132 raise signals.TestFailure('Thread %d timedout' % index) 133 134 for index in range(0, len(self.download_threads_result)): 135 if not self.download_threads_result[index]: 136 self.log.info("Download failed for %d" % index) 137 raise signals.TestFailure('Thread %d failed to download' % 138 index) 139 return False 140 141 return True 142 143 def test_one_large_multiple_small_downloads(self): 144 for index in range(self.num_of_iterations): 145 download_threads = [] 146 try: 147 large_thread = threading.Thread( 148 target=self.download_thread, 149 args=(self.download_large_url, )) 150 download_threads.append(large_thread) 151 large_thread.start() 152 153 for i in range(self.num_of_small_downloads): 154 # Start small file download 155 t = threading.Thread(target=self.download_thread, 156 args=(self.download_small_url, )) 157 download_threads.append(t) 158 t.start() 159 # Wait for thread to exit before starting the next iteration 160 t.join(self.download_timeout_s) 161 162 # Wait for the large file download thread to complete 163 large_thread.join(self.download_timeout_s) 164 165 finally: 166 is_alive = False 167 168 for index, t in enumerate(download_threads): 169 if t.isAlive(): 170 t = None 171 is_alive = True 172 173 if is_alive: 174 raise signals.TestFailure('Thread %d timedout' % index) 175 176 for index in range(0, len(self.download_threads_result)): 177 if not self.download_threads_result[index]: 178 self.log.info("Download failed for %d" % index) 179 raise signals.TestFailure('Thread %d failed to download' % 180 index) 181 return False 182 183 # Clear results before looping again 184 self.download_threads_result.clear() 185 186 return True 187