def test_ndt_result_increments_time_correctly(self): # Create a list of times every minute starting at 2016-1-1 8:00:00 and # ending at 2016-1-1 8:04:00. These will be the values that our mock # datetime.now() function returns. base_date = datetime.datetime(2016, 1, 1, 8, 0, 0, tzinfo=pytz.utc) dates = [base_date + datetime.timedelta(0, 60) * x for x in range(6)] with mock.patch.object(html5_driver.datetime, 'datetime', autospec=True) as mocked_datetime: mocked_datetime.now.side_effect = dates result = html5_driver.NdtHtml5SeleniumDriver( browser='firefox', url='http://ndt.mock-server.com:7123/', timeout=1).perform_test() # And the sequence of returned values follows the expected timeline # that the readings are taken in. # yapf: disable self.assertEqual( result.start_time, datetime.datetime(2016, 1, 1, 8, 0, 0, tzinfo=pytz.utc)) self.assertEqual( result.c2s_result.start_time, datetime.datetime(2016, 1, 1, 8, 1, 0, tzinfo=pytz.utc)) self.assertEqual( result.s2c_result.start_time, datetime.datetime(2016, 1, 1, 8, 3, 0, tzinfo=pytz.utc)) self.assertEqual( result.end_time, datetime.datetime(2016, 1, 1, 8, 5, 0, tzinfo=pytz.utc))
def test_invalid_throughput_unit_raises_error(self): class NewDriver(object): def get(self, url): pass def close(self): pass def find_element_by_id(self, id): if id == 'download-speed-units': return mock.Mock(text='Gb/s', autospec=True) elif id == 'download-speed': return mock.Mock(text='72', autospec=True) elif id == 'upload-speed-units': return mock.Mock(text='not a unit', autospec=True) else: return mock.Mock(text='34', autospec=True) def find_elements_by_xpath(self, xpath): return [mock.Mock(autospec=True)] with mock.patch.object(html5_driver.webdriver, 'Firefox', autospec=True, return_value=NewDriver()): # And a value error is raised because the c2s throughput # unit was invalid. with self.assertRaises(ValueError): html5_driver.NdtHtml5SeleniumDriver( browser='firefox', url='http://ndt.mock-server.com:7123/', timeout=1000).perform_test()
def test_results_page_displays_non_numeric_latency(self): class NewDriver(object): def get(self, url): pass def close(self): pass def find_element_by_id(self, id): if id == 'upload-speed-units': return mock.Mock(text='kb/s', autospec=True) elif id == 'download-speed-units': return mock.Mock(text='Mb/s', autospec=True) elif id == 'latency': return mock.Mock(text='Non-numeric value', autospec=True) else: return mock.Mock(text='34', autospec=True) def find_elements_by_xpath(self, xpath): return [mock.Mock(autospec=True)] with mock.patch.object(html5_driver.webdriver, 'Firefox', autospec=True, return_value=NewDriver()): test_results = html5_driver.NdtHtml5SeleniumDriver( browser='firefox', url='http://ndt.mock-server.com:7123/', timeout=1000).perform_test() # And the appropriate error object is contained in the list self.assertEqual(len(test_results.errors), 1) self.assertEqual(test_results.errors[0].message, 'illegal value shown for latency: Non-numeric value')
def test_unrecognized_browser_raises_error(self): selenium_driver = html5_driver.NdtHtml5SeleniumDriver( browser='not_a_browser', url='http://ndt.mock-server.com:7123', timeout=1) with self.assertRaises(ValueError): selenium_driver.perform_test()
def test_results_page_displays_non_numeric_metrics(self): """A results page with non-numeric metrics results in error list errors. When latency, c2s_throughput, and s2c_throughput are all non-numeric values, corresponding error objects are added to the errors list that indicate that each of these values is invalid. """ self.mock_page_elements['upload-speed'] = mock.Mock( text='Non-numeric value') self.mock_page_elements['download-speed'] = mock.Mock( text='Non-numeric value') self.mock_page_elements['latency'] = mock.Mock( text='Non-numeric value') result = html5_driver.NdtHtml5SeleniumDriver( browser='firefox', url='http://ndt.mock-server.com:7123/', timeout=1000).perform_test() self.assertIsNone(result.c2s_result.throughput) self.assertIsNone(result.s2c_result.throughput) self.assertIsNone(result.latency) self.assertErrorMessagesEqual([ 'illegal value shown for c2s throughput: Non-numeric value', 'illegal value shown for s2c throughput: Non-numeric value', 'illegal value shown for latency: Non-numeric value' ], result.errors)
def test_results_page_displays_numeric_latency(self): """A valid (numeric) latency results in an empty errors list.""" # Mock so always returns a numeric value for a WebElement.text attribute class NewDriver(object): def get(self, url): pass def close(self): pass def find_element_by_id(self, id): if id == 'download-speed-units': return mock.Mock(text='Mb/s', autospec=True) elif id == 'upload-speed-units': return mock.Mock(text='Mb/s', autospec=True) return mock.Mock(text='72', autospec=True) def find_elements_by_xpath(self, xpath): return [mock.Mock(autospec=True)] with mock.patch.object(html5_driver.webdriver, 'Firefox', autospec=True, return_value=NewDriver()): test_results = html5_driver.NdtHtml5SeleniumDriver( browser='firefox', url='http://ndt.mock-server.com:7123/', timeout=1000).perform_test() self.assertEqual(test_results.latency, 72.0) # And an error object is not contained in the list self.assertEqual(len(test_results.errors), 0)
def test_reading_in_result_page_timeout_throws_error(self): # If a timeout exception occurs when the driver attempts to # read the metric page class NewDriver(object): def get(self, url): pass def close(self): pass def find_element_by_id(self, id): if id == 'upload-speed': raise exceptions.TimeoutException else: return mock.Mock(text='34', autospec=True) def find_elements_by_xpath(self, xpath): return [mock.Mock(autospec=True)] with mock.patch.object(html5_driver.webdriver, 'Firefox', autospec=True, return_value=NewDriver()): test_results = html5_driver.NdtHtml5SeleniumDriver( browser='firefox', url='http://ndt.mock-server.com:7123/', timeout=1000).perform_test() # The appropriate error object is contained in the list. self.assertEqual(test_results.errors[0].message, 'Test did not complete within timeout period.')
def test_invalid_URL_throws_error(self): self.mock_driver.get.side_effect = ( exceptions.WebDriverException('Failed to load test UI.')) result = html5_driver.NdtHtml5SeleniumDriver(browser='firefox', url='invalid_url', timeout=1).perform_test() self.assertErrorMessagesEqual(['Failed to load test UI.'], result.errors)
def test_ndt_test_results_increments_time_correctly(self): # Create a list of times every minute starting at 2016-1-1 8:00:00 # and ending at 2016-1-1 8:04:00. These will be the values that our # mock datetime.now() function returns. base_date = datetime.datetime(2016, 1, 1, 8, 0, 0, tzinfo=pytz.utc) dates = [base_date + datetime.timedelta(0, 60) * x for x in range(6)] class NewDriver(object): def get(self, url): pass def close(self): pass def find_element_by_id(self, id): if id == 'upload-speed-units': return mock.Mock(text='kb/s', autospec=True) elif id == 'upload-speed': return mock.Mock(text='72', autospec=True) elif id == 'download-speed-units': return mock.Mock(text='Mb/s', autospec=True) else: return mock.Mock(text='34', autospec=True) def find_elements_by_xpath(self, xpath): return [mock.Mock(autospec=True)] mock_driver = mock.patch.object(html5_driver.webdriver, 'Firefox', autospec=True, return_value=NewDriver()) mock_driver.start() with mock.patch.object(html5_driver.datetime, 'datetime', autospec=True) as mocked_datetime: mocked_datetime.now.side_effect = dates test_results = html5_driver.NdtHtml5SeleniumDriver( browser='firefox', url='http://ndt.mock-server.com:7123/', timeout=1).perform_test() mock_driver.stop() # And the sequence of returned values follows the expected timeline # that the readings are taken in. self.assertEqual( test_results.start_time, datetime.datetime(2016, 1, 1, 8, 0, 0, tzinfo=pytz.utc)) self.assertEqual( test_results.c2s_result.start_time, datetime.datetime(2016, 1, 1, 8, 1, 0, tzinfo=pytz.utc)) self.assertEqual( test_results.s2c_result.start_time, datetime.datetime(2016, 1, 1, 8, 3, 0, tzinfo=pytz.utc)) self.assertEqual( test_results.end_time, datetime.datetime(2016, 1, 1, 8, 5, 0, tzinfo=pytz.utc))
def test_test_yields_valid_results_when_all_page_elements_are_expected_values( self): result = html5_driver.NdtHtml5SeleniumDriver( browser='firefox', url='http://ndt.mock-server.com:7123/').perform_test() self.assertEqual(1.0, result.c2s_result.throughput) self.assertEqual(2.0, result.s2c_result.throughput) self.assertEqual(3.0, result.latency) self.assertErrorMessagesEqual([], result.errors)
def test_invalid_throughput_unit_raises_error(self): self.mock_page_elements['upload-speed-units'] = mock.Mock( text='not a unit') # And a value error is raised because the c2s throughput unit was # invalid. with self.assertRaises(ValueError): html5_driver.NdtHtml5SeleniumDriver( browser='firefox', url='http://ndt.mock-server.com:7123/', timeout=1000).perform_test()
def test_safari_driver_can_be_used_for_test(self, mock_safari): mock_safari.return_value = self.mock_driver result = html5_driver.NdtHtml5SeleniumDriver( browser='safari', url='http://ndt.mock-server.com:7123/', timeout=1000).perform_test() self.assertEqual(1.0, result.c2s_result.throughput) self.assertEqual(2.0, result.s2c_result.throughput) self.assertEqual(3.0, result.latency) self.assertErrorMessagesEqual([], result.errors)
def test_results_page_displays_non_numeric_latency(self): self.mock_page_elements['latency'] = mock.Mock(text='Non-numeric value') result = html5_driver.NdtHtml5SeleniumDriver( browser='firefox', url='http://ndt.mock-server.com:7123/').perform_test() self.assertEqual(1.0, result.c2s_result.throughput) self.assertEqual(2.0, result.s2c_result.throughput) self.assertIsNone(result.latency) self.assertErrorMessagesEqual( ['illegal value shown for latency: Non-numeric value'], result.errors)
def test_invalid_throughput_unit_yields_error(self): self.mock_page_elements['upload-speed-units'] = mock.Mock(text='banana') result = html5_driver.NdtHtml5SeleniumDriver( browser='firefox', url='http://ndt.mock-server.com:7123/').perform_test() self.assertIsNone(result.c2s_result.throughput) self.assertEqual(2.0, result.s2c_result.throughput) self.assertEqual(3.0, result.latency) self.assertErrorMessagesEqual( ['Invalid throughput unit specified: banana'], result.errors)
def test_fails_gracefully_when_start_button_not_in_dom(self): self.mock_elements_by_text['Start Test'] = None result = html5_driver.NdtHtml5SeleniumDriver( browser='firefox', url='http://ndt.mock-server.com:7123/').perform_test() self.assertIsNone(result.c2s_result.throughput) self.assertIsNone(result.s2c_result.throughput) self.assertIsNone(result.latency) self.assertErrorMessagesEqual( [html5_driver.ERROR_START_BUTTON_NOT_IN_DOM], result.errors)
def test_test_in_progress_timeout_throws_error(self): # Call to webdriverwait throws timeout exception with mock.patch.object(html5_driver.ui, 'WebDriverWait', side_effect=exceptions.TimeoutException, autospec=True): result = html5_driver.NdtHtml5SeleniumDriver( browser='firefox', url='http://ndt.mock-server.com:7123/', timeout=1).perform_test() self.assertErrorMessagesEqual( ['Test did not complete within timeout period.'], result.errors)
def test_invalid_URL_throws_error(self): self.mock_browser.get.side_effect = exceptions.WebDriverException( u'Failed to load test UI.') test_results = html5_driver.NdtHtml5SeleniumDriver( browser='firefox', url='invalid_url', timeout=1).perform_test() # We have one error self.assertEqual(len(test_results.errors), 1) # And that error is about test UI loading failure self.assertEqual(test_results.errors[0].message, 'Failed to load test UI.')
def test_ndt_result_increments_time_correctly(self): # Create a list of mock times to be returned by datetime.now(). times = [] for i in range(11): times.append(datetime.datetime(2016, 1, 1, 0, 0, i)) with mock.patch.object(html5_driver.datetime, 'datetime', autospec=True) as mocked_datetime: # Patch datetime.now to return the next mock time on every call to # now(). mocked_datetime.now.side_effect = times # Modify the create_browser mock to increment the clock forward one # call. @contextlib.contextmanager def mock_create_browser(unused_browser_name): datetime.datetime.now(pytz.utc) yield self.mock_driver browser_client_common.create_browser.side_effect = ( mock_create_browser) # Modify the wait_until_element_is_visible mock to increment the # clock forward one call. def mock_visibility_of(unused_driver, unused_element, unused_timeout): datetime.datetime.now(pytz.utc) return True html5_driver.browser_client_common.wait_until_element_is_visible.side_effect = ( mock_visibility_of) result = html5_driver.NdtHtml5SeleniumDriver( browser='firefox', url='http://ndt.mock-server.com:7123/').perform_test() # Verify the recorded times matches the expected sequence. self.assertEqual(times[0], result.start_time) # times[1] is the call from mock_firefox # times[2] is the check for visibility of "Start Test" button # times[3] is the check for visibility of c2s test start self.assertEqual(times[4], result.c2s_result.start_time) # times[5] is the check for visibility of s2c test start (start of s2c # marks the end of c2s) self.assertEqual(times[6], result.c2s_result.end_time) self.assertEqual(times[7], result.s2c_result.start_time) # times[8] is the check for visibility of results page self.assertEqual(times[9], result.s2c_result.end_time) self.assertEqual(times[10], result.end_time)
def test_c2s_start_timeout_yields_errors(self): """If waiting for just c2s start times out, expect just one error.""" html5_driver.browser_client_common.wait_until_element_is_visible.side_effect = [ True, # "Start Test" button False, # Upload speed label True, # Download speed label True, # Results div ] result = html5_driver.NdtHtml5SeleniumDriver( browser='firefox', url='http://ndt.mock-server.com:7123/').perform_test() self.assertErrorMessagesEqual( [browser_client_common.ERROR_C2S_NEVER_STARTED], result.errors)
def test_results_page_displays_non_numeric_metrics(self): """A results page with non-numeric metrics results in error list errors. When latency, c2s_throughput, and s2c_throughput are all non-numeric values, corresponding error objects are added to the errors list that indicate that each of these values is invalid. """ # We patch selenium's web driver so it always has a non numeric # value as a WebElement.text attribute class NewWebElement(object): def __init__(self): self.text = 'Non numeric value' def click(self): pass class NewDriver(object): def get(self, url): pass def close(self): pass def find_element_by_id(self, id): return NewWebElement() def find_elements_by_xpath(self, xpath): return [NewWebElement()] with mock.patch.object(html5_driver.webdriver, 'Firefox', autospec=True, return_value=NewDriver()): test_results = html5_driver.NdtHtml5SeleniumDriver( browser='firefox', url='http://ndt.mock-server.com:7123/', timeout=1000).perform_test() # And the appropriate error objects are contained in # the list self.assertEqual( test_results.errors[0].message, 'illegal value shown for c2s throughput: Non numeric value') self.assertEqual( test_results.errors[1].message, 'illegal value shown for s2c throughput: Non numeric value') self.assertEqual(test_results.errors[2].message, 'illegal value shown for latency: Non numeric value')
def test_ndt_result_records_todays_times(self): # When we patch datetime so it shows our current date as 2016-01-01 self.assertEqual(datetime.datetime.now(), datetime.datetime(2016, 1, 1)) result = html5_driver.NdtHtml5SeleniumDriver( browser='firefox', url='http://ndt.mock-server.com:7123/', timeout=1000).perform_test() # Then the readings for our test start and end times occur within # today's date self.assertEqual(result.start_time, datetime.datetime(2016, 1, 1, tzinfo=pytz.utc)) self.assertEqual(result.end_time, datetime.datetime(2016, 1, 1, tzinfo=pytz.utc))
def test_fails_gracefully_if_wait_for_start_button_times_out(self): # Simulate a webdriver timeout when waiting for any element to appear, # including the "Start Test" button. html5_driver.browser_client_common.wait_until_element_is_visible.return_value = ( False) result = html5_driver.NdtHtml5SeleniumDriver( browser='firefox', url='http://ndt.mock-server.com:7123/').perform_test() self.assertIsNone(result.c2s_result.throughput) self.assertIsNone(result.s2c_result.throughput) self.assertIsNone(result.latency) self.assertErrorMessagesEqual( [html5_driver.ERROR_TIMED_OUT_WAITING_FOR_START_BUTTON], result.errors)
def test_c2s_kbps_speed_conversion(self): """Test c2s speed converts from kb/s to Mb/s correctly.""" # If c2s speed is 72 kb/s and s2c speed is 34 in the browser self.mock_page_elements['upload-speed'] = mock.Mock(text='72') self.mock_page_elements['upload-speed-units'] = mock.Mock(text='kb/s') self.mock_page_elements['download-speed'] = mock.Mock(text='34') self.mock_page_elements['download-speed-units'] = mock.Mock(text='Mb/s') result = html5_driver.NdtHtml5SeleniumDriver( browser='firefox', url='http://ndt.mock-server.com:7123/').perform_test() # Then c2s is converted from kb/s to Mb/s self.assertEqual(0.072, result.c2s_result.throughput) # And s2c is not self.assertEqual(34.0, result.s2c_result.throughput) self.assertEqual(3.0, result.latency) self.assertErrorMessagesEqual([], result.errors)
def test_test_in_progress_timeout_throws_error(self): # Call to webdriverwait throws timeout exception with mock.patch.object(html5_driver.ui, 'WebDriverWait', side_effect=exceptions.TimeoutException, autospec=True): test_results = html5_driver.NdtHtml5SeleniumDriver( browser='firefox', url='http://ndt.mock-server.com:7123/', timeout=1).perform_test() # We have one error self.assertEqual(len(test_results.errors), 1) # And that is a timout error self.assertEqual(test_results.errors[0].message, 'Test did not complete within timeout period.')
def test_test_in_progress_timeout_yields_timeout_errors(self): """If each test times out, expect an error for each timeout.""" # Make the "Start Test" button visible, but others time out. html5_driver.browser_client_common.wait_until_element_is_visible.side_effect = [ True, # "Start Test" button False, # Upload speed label False, # Download speed label False, # Results div ] result = html5_driver.NdtHtml5SeleniumDriver( browser='firefox', url='http://ndt.mock-server.com:7123/').perform_test() self.assertErrorMessagesEqual( [browser_client_common.ERROR_C2S_NEVER_STARTED, browser_client_common.ERROR_S2C_NEVER_STARTED, browser_client_common.ERROR_S2C_NEVER_ENDED], result.errors)
def test_reading_in_result_page_timeout_throws_error(self): # Simulate a timeout exception when the driver attempts to read the # metric page. def mock_find_element_by_id(id): if id == 'upload-speed': raise exceptions.TimeoutException return self.mock_page_elements[id] self.mock_driver.find_element_by_id.side_effect = ( mock_find_element_by_id) result = html5_driver.NdtHtml5SeleniumDriver( browser='firefox', url='http://ndt.mock-server.com:7123/', timeout=1000).perform_test() self.assertIsNone(result.c2s_result.throughput) self.assertIsNone(result.s2c_result.throughput) self.assertIsNone(result.latency) self.assertErrorMessagesEqual( ['Test did not complete within timeout period.'], result.errors)
def test_c2s_kbps_speed_conversion(self): """Test c2s speed converts from kb/s to Mb/s correctly.""" # If c2s speed is 72 kb/s and s2c speed is 34 in the browser class NewDriver(object): def get(self, url): pass def close(self): pass def find_element_by_id(self, id): if id == 'upload-speed-units': return mock.Mock(text='kb/s', autospec=True) elif id == 'upload-speed': return mock.Mock(text='72', autospec=True) elif id == 'download-speed-units': return mock.Mock(text='Mb/s', autospec=True) else: return mock.Mock(text='34', autospec=True) def find_elements_by_xpath(self, xpath): return [mock.Mock(autospec=True)] with mock.patch.object(html5_driver.webdriver, 'Firefox', autospec=True, return_value=NewDriver()): test_results = html5_driver.NdtHtml5SeleniumDriver( browser='firefox', url='http://ndt.mock-server.com:7123/', timeout=1000).perform_test() # Then c2s is converted from kb/s to Mb/s self.assertEqual(test_results.c2s_result.throughput, 0.072) # And s2c is not self.assertEqual(test_results.s2c_result.throughput, 34) # And an error object is not contained in the list self.assertEqual(len(test_results.errors), 0)
def test_ndt_test_results_records_todays_times(self): class NewDriver(object): def get(self, url): pass def close(self): pass def find_element_by_id(self, id): if id == 'upload-speed-units': return mock.Mock(text='kb/s', autospec=True) elif id == 'download-speed-units': return mock.Mock(text='Mb/s', autospec=True) elif id == 'upload-speed' or 'download-speed': return mock.Mock(text='72', autospec=True) else: return mock.Mock(autospec=True) def find_elements_by_xpath(self, xpath): return [mock.Mock(autospec=True)] # When we patch datetime so it shows our current date as 2016-01-01 self.assertEqual(datetime.datetime.now(), datetime.datetime(2016, 1, 1)) with mock.patch.object(html5_driver.webdriver, 'Firefox', autospec=True, return_value=NewDriver()): test_results = html5_driver.NdtHtml5SeleniumDriver( browser='firefox', url='http://ndt.mock-server.com:7123/', timeout=1000).perform_test() # Then the readings for our test start and end times occur within # today's date self.assertEqual(test_results.start_time, datetime.datetime(2016, 1, 1, tzinfo=pytz.utc)) self.assertEqual(test_results.end_time, datetime.datetime(2016, 1, 1, tzinfo=pytz.utc))
def test_safari_driver_can_be_used_for_test(self): class NewDriver(object): def get(self, url): pass def close(self): pass def find_elements_by_xpath(self, xpath): return [mock.Mock(autospec=True)] def find_element_by_id(self, id): if id == 'download-speed-units': return mock.Mock(text='Gb/s', autospec=True) elif id == 'download-speed': return mock.Mock(text='72', autospec=True) elif id == 'upload-speed-units': return mock.Mock(text='Mb/s', autospec=True) else: return mock.Mock(text='34', autospec=True) with mock.patch.object(html5_driver.webdriver, 'Safari', autospec=True, return_value=NewDriver()): test_results = html5_driver.NdtHtml5SeleniumDriver( browser='safari', url='http://ndt.mock-server.com:7123/', timeout=1000).perform_test() # Then s2c is converted from Gb/s to Mb/s self.assertEqual(test_results.s2c_result.throughput, 72000) # And c2s is not self.assertEqual(test_results.c2s_result.throughput, 34) # And an error object is not contained in the list self.assertEqual(len(test_results.errors), 0)