def _click_start_button(driver, errors): """Clicks the "Start Test" button in the web UI. Args: driver: An instance of a Selenium webdriver browser class. errors: An errors list. Returns: True if the "Start Test" button could be successfully located and clicked. """ start_button = browser_client_common.find_element_containing_text( driver, 'Start Test') if not start_button: errors.append(results.TestError(ERROR_START_BUTTON_NOT_IN_DOM)) logger.error(ERROR_START_BUTTON_NOT_IN_DOM) return False if not browser_client_common.wait_until_element_is_visible( driver, start_button, browser_client_common.UI_WAIT_TIMEOUT): errors.append( results.TestError(ERROR_TIMED_OUT_WAITING_FOR_START_BUTTON)) logger.error(ERROR_TIMED_OUT_WAITING_FOR_START_BUTTON) return False start_button.click() return True
def _complete_ui_flow(driver, url, result): """Performs the UI flow for the NDT HTML5 test and records results. Args: driver: An instance of a Selenium webdriver browser class. url: URL to load to start the UI flow. result: NdtResult instance to populate with results from proceeding through the UI flow. """ logger.info('loading URL: %s', url) if not browser_client_common.load_url(driver, url, result.errors): return logger.info('page loaded, starting UI flow') _click_websocket_button(driver) # If we can't click the start button, nothing left to do, so bail out. if not _click_start_button(driver, result.errors): return logger.info('clicked "Start Test" button') result.c2s_result = results.NdtSingleTestResult() result.s2c_result = results.NdtSingleTestResult() if _wait_for_c2s_test_to_start(driver): result.c2s_result.start_time = datetime.datetime.now(pytz.utc) logger.info('c2s test started') else: result.errors.append( results.TestError(browser_client_common.ERROR_C2S_NEVER_STARTED)) logger.error(browser_client_common.ERROR_C2S_NEVER_STARTED) if _wait_for_s2c_test_to_start(driver): result.c2s_result.end_time = datetime.datetime.now(pytz.utc) logger.info('c2s test finished') result.s2c_result.start_time = datetime.datetime.now(pytz.utc) logger.info('s2c test started') else: result.errors.append( results.TestError(browser_client_common.ERROR_S2C_NEVER_STARTED)) logger.error(browser_client_common.ERROR_S2C_NEVER_STARTED) if _wait_for_results_page_to_appear(driver): result.s2c_result.end_time = datetime.datetime.now(pytz.utc) logger.info('s2c test finished') else: result.errors.append( results.TestError(browser_client_common.ERROR_S2C_NEVER_ENDED)) logger.error(browser_client_common.ERROR_S2C_NEVER_ENDED) _populate_metric_values(result, driver)
def _parse_throughput(errors, throughput, throughput_units, throughput_metric_name): """Converts metric into a valid numeric value in Mb/s . For a given metric, checks that it is a valid numeric value. If not, an error is added to the list contained in the NdtResult instance attribute. If it is, it is converted into Mb/s where necessary. Args: errors: An errors list. throughput: The throughput value that is to be evaluated. throughput_units: The units for the throughput value that is to be evaluated (one of kb/s, Mb/s, Gb/s). throughput_metric_name: A string representing the name of the throughput metric to validate. Returns: float representing the converted metric, None if an illegal value is given. """ if _convert_metric_to_float(errors, throughput, throughput_metric_name): throughput = float(throughput) if throughput_units == 'kb/s': converted_throughput = throughput / 1000 return converted_throughput elif throughput_units == 'Gb/s': converted_throughput = throughput * 1000 return converted_throughput elif throughput_units == 'Mb/s': return throughput else: errors.append( results.TestError('Invalid throughput unit specified: %s' % throughput_units)) return None
def load_url(driver, url, errors): """Loads the URL in a Selenium driver for an NDT test. Args: driver: An instance of a Selenium webdriver. url: The URL to load. errors: A list of errors that will be appended to if the URL cannot be loaded. Returns: True if loading the URL was successful. """ try: driver.get(url) except (exceptions.WebDriverException, exceptions.TimeoutException) as e: if type(e) is exceptions.TimeoutException: errors.append( results.TestError(ERROR_TIMED_OUT_WAITING_FOR_PAGE_LOAD)) errors.append(results.TestError(ERROR_FAILED_TO_LOAD_URL_FORMAT % url)) return False return True
def _load_url(driver, url, result): """Loads the URL in a Selenium driver for an NDT test. Args: driver: An instance of a Selenium webdriver. url: The The URL of an NDT server to test against. result: An instance of NdtResult. Returns: True if loading the URL was successful, False if otherwise. """ try: driver.get(url) except exceptions.WebDriverException: result.errors.append(results.TestError('Failed to load test UI.')) return False return True
def _record_test_in_progress_values(result, driver, timeout): """Records values that are measured while the NDT test is in progress. Measures s2c_start_time, c2s_end_time, and end_time, which are stored in an instance of NdtResult. These times are measured while the NDT test is in progress. Args: result: An instance of NdtResult. driver: An instance of a Selenium webdriver browser class. timeout: The number of seconds that the driver will wait for each element to become visible before timing out. Returns: True if recording the measured values was successful, False if otherwise. """ try: # wait until 'Now Testing your upload speed' is displayed upload_speed_text = driver.find_elements_by_xpath( "//*[contains(text(), 'your upload speed')]")[0] result.c2s_result = results.NdtSingleTestResult() result.c2s_result.start_time = _record_time_when_element_displayed( upload_speed_text, driver, timeout=timeout) result.c2s_result.end_time = datetime.datetime.now(pytz.utc) # wait until 'Now Testing your download speed' is displayed download_speed_text = driver.find_elements_by_xpath( "//*[contains(text(), 'your download speed')]")[0] result.s2c_result = results.NdtSingleTestResult() result.s2c_result.start_time = _record_time_when_element_displayed( download_speed_text, driver, timeout=timeout) # wait until the results page appears results_text = driver.find_element_by_id('results') result.s2c_result.end_time = datetime.datetime.now(pytz.utc) result.end_time = _record_time_when_element_displayed(results_text, driver, timeout=timeout) except exceptions.TimeoutException: message = 'Test did not complete within timeout period.' result.errors.append( results.TestError(datetime.datetime.now(pytz.utc), message)) return False return True
def _populate_metric_values(result, driver): """Populates NdtResult with metrics from page, checks values are valid. Populates the NdtResult instance with metrics from the NDT test page. Checks thatthe values for upload (c2s) throughput, download (s2c) throughput, and latency within the NdtResult instance dict are valid. Args: result: An instance of NdtResult. driver: An instance of a Selenium webdriver browser class. Returns: True if populating metrics and checking their values was successful. False if otherwise. """ try: c2s_throughput = driver.find_element_by_id('upload-speed').text c2s_throughput_units = driver.find_element_by_id( 'upload-speed-units').text result.c2s_result.throughput = _parse_throughput( result.errors, c2s_throughput, c2s_throughput_units, 'c2s throughput') s2c_throughput = driver.find_element_by_id('download-speed').text s2c_throughput_units = driver.find_element_by_id( 'download-speed-units').text result.s2c_result.throughput = _parse_throughput( result.errors, s2c_throughput, s2c_throughput_units, 's2c throughput') result.latency = driver.find_element_by_id('latency').text result.latency = _validate_metric(result.errors, result.latency, 'latency') except exceptions.TimeoutException: message = 'Test did not complete within timeout period.' result.errors.append( results.TestError(datetime.datetime.now(pytz.utc), message)) return False return True
def _convert_metric_to_float(errors, metric, metric_name): """Converts a given metric to a float, otherwise, adds an error object. If a given metric can be converted to a float, it is converted. Otherwise, a TestError object is added to errors. Args: errors: An errors list. metric: The value of the metric that is to be evaluated. metric_name: A string representing the name of the metric to validate. Returns: True if the validation was successful. """ try: float(metric) except ValueError: errors.append( results.TestError('illegal value shown for %s: %s' % (metric_name, metric))) return False return True
def _decode_error(error): """Decodes a dictionary into a TestError instance.""" return results.TestError(error['message'], _decode_time(error['timestamp']))
def _add_test_error(self, error_message): self._result.errors.append(results.TestError(error_message)) logger.error(error_message)