| # Copyright 2018 The Chromium Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| import json |
| import logging |
| import unittest |
| from unittest import mock |
| from unittest.mock import call |
| |
| from core import results_dashboard |
| |
| |
| class ResultsDashboardTest(unittest.TestCase): |
| |
| def setUp(self): |
| self.dummy_token_generator = lambda: 'Arthur-Merlin' |
| self.perf_data = {'foo': 1, 'bar': 2} |
| self.dashboard_url = 'https://chromeperf.appspot.com' |
| self.dummy_token = {'token': 'dummy1234', 'file': 'path/to/file'} |
| |
| def testRetryForSendResultRetryException(self): |
| |
| def raise_retry_exception(url, histogramset_json, token_generator_callback): |
| del url, histogramset_json # unused |
| del token_generator_callback # unused |
| raise results_dashboard.SendResultsRetryException('Should retry') |
| |
| with mock.patch('core.results_dashboard.time.sleep') as sleep_mock: |
| with mock.patch( |
| 'core.results_dashboard._SendHistogramJson', |
| side_effect=raise_retry_exception) as m: |
| upload_result = results_dashboard.SendResults( |
| self.perf_data, |
| 'dummy_benchmark', |
| self.dashboard_url, |
| send_as_histograms=True, |
| token_generator_callback=self.dummy_token_generator, |
| num_retries=5) |
| self.assertFalse(upload_result) |
| self.assertEqual(m.call_count, 5) |
| self.assertEqual( |
| sleep_mock.mock_calls, |
| [call(15), call(30), |
| call(60), call(120), |
| call(240)]) |
| |
| def testNoRetryForSendResultFatalException(self): |
| |
| def raise_retry_exception(url, histogramset_json, token_generator_callback): |
| del url, histogramset_json # unused |
| del token_generator_callback # unused |
| raise results_dashboard.SendResultsFatalException('Do not retry') |
| |
| with mock.patch('core.results_dashboard.time.sleep') as sleep_mock: |
| with mock.patch( |
| 'core.results_dashboard._SendHistogramJson', |
| side_effect=raise_retry_exception) as m: |
| upload_result = results_dashboard.SendResults( |
| self.perf_data, |
| 'dummy_benchmark', |
| self.dashboard_url, |
| send_as_histograms=True, |
| token_generator_callback=self.dummy_token_generator, |
| num_retries=5) |
| self.assertFalse(upload_result) |
| self.assertEqual(m.call_count, 1) |
| self.assertFalse(sleep_mock.mock_calls) |
| |
| def testNoRetryForSuccessfulSendResult(self): |
| with mock.patch('core.results_dashboard.time.sleep') as sleep_mock: |
| with mock.patch('core.results_dashboard._SendHistogramJson') as m: |
| upload_result = results_dashboard.SendResults( |
| self.perf_data, |
| 'dummy_benchmark', |
| self.dashboard_url, |
| send_as_histograms=True, |
| token_generator_callback=self.dummy_token_generator, |
| num_retries=5) |
| self.assertTrue(upload_result) |
| self.assertEqual(m.call_count, 1) |
| self.assertFalse(sleep_mock.mock_calls) |
| |
| def testNoRetryAfterSucessfulSendResult(self): |
| counter = [0] |
| |
| def raise_retry_exception_first_two_times(url, histogramset_json, |
| token_generator_callback): |
| del url, histogramset_json # unused |
| del token_generator_callback # unused |
| counter[0] += 1 |
| if counter[0] <= 2: |
| raise results_dashboard.SendResultsRetryException('Please retry') |
| |
| with mock.patch('core.results_dashboard.time.sleep') as sleep_mock: |
| with mock.patch( |
| 'core.results_dashboard._SendHistogramJson', |
| side_effect=raise_retry_exception_first_two_times) as m: |
| upload_result = results_dashboard.SendResults( |
| self.perf_data, |
| 'dummy_benchmark', |
| self.dashboard_url, |
| send_as_histograms=True, |
| token_generator_callback=self.dummy_token_generator, |
| num_retries=5) |
| self.assertTrue(upload_result) |
| self.assertEqual(m.call_count, 3) |
| self.assertEqual(sleep_mock.mock_calls, [call(15), call(30)]) |
| |
| def testSendHistogramJsonRetryException(self): |
| |
| def request(*args, **kwargs): |
| del args, kwargs |
| content = json.dumps(self.dummy_token) |
| |
| class Response(object): |
| status = 403 |
| reason = 'dummy auth error' |
| |
| return Response(), content |
| |
| with mock.patch('core.results_dashboard.time.sleep') as sleep_mock: |
| with mock.patch.object( |
| results_dashboard.httplib2.Http, 'request', new=request): |
| upload_result = results_dashboard.SendResults( |
| self.perf_data, |
| 'dummy_benchmark', |
| self.dashboard_url, |
| send_as_histograms=True, |
| token_generator_callback=self.dummy_token_generator, |
| num_retries=5) |
| self.assertFalse(upload_result) |
| self.assertEqual( |
| sleep_mock.mock_calls, |
| [call(15), call(30), |
| call(60), call(120), |
| call(240)]) |
| |
| def testSendHistogramJsonTypeWarning(self): |
| |
| def request(*args, **kwargs): |
| del args, kwargs |
| content = 'non json response' |
| |
| class Response(object): |
| status = 200 |
| |
| return Response(), content |
| |
| with mock.patch('core.results_dashboard.time.sleep') as sleep_mock: |
| with mock.patch.object( |
| results_dashboard.httplib2.Http, 'request', new=request): |
| |
| upload_result = results_dashboard.SendResults( |
| self.perf_data, |
| 'dummy_benchmark', |
| self.dashboard_url, |
| send_as_histograms=True, |
| token_generator_callback=self.dummy_token_generator, |
| num_retries=5) |
| |
| # upload should still be successful, despite failing to fetch token. |
| self.assertTrue(upload_result) |
| self.assertFalse(sleep_mock.mock_calls) |
| |
| def testSendHistogramJsonValueWarning(self): |
| |
| def request(*args, **kwargs): |
| del args, kwargs |
| content = json.dumps(None) |
| |
| class Response(object): |
| status = 200 |
| |
| return Response(), content |
| |
| with mock.patch('core.results_dashboard.time.sleep') as sleep_mock: |
| with mock.patch.object( |
| results_dashboard.httplib2.Http, 'request', new=request): |
| |
| upload_result = results_dashboard.SendResults( |
| self.perf_data, |
| 'dummy_benchmark', |
| self.dashboard_url, |
| send_as_histograms=True, |
| token_generator_callback=self.dummy_token_generator, |
| num_retries=5) |
| |
| # upload should still be successful, despite failing to fetch token. |
| self.assertTrue(upload_result) |
| self.assertFalse(sleep_mock.mock_calls) |
| |
| def testSuccessfulSendHistogramJson(self): |
| |
| def request(*args, **kwargs): |
| del args, kwargs |
| content = json.dumps(self.dummy_token) |
| |
| class Response(object): |
| status = 200 |
| |
| return Response(), content |
| |
| with mock.patch('core.results_dashboard.time.sleep') as sleep_mock: |
| with mock.patch.object( |
| results_dashboard.httplib2.Http, 'request', new=request): |
| with mock.patch.object(logging, 'info') as log_mock: |
| |
| upload_result = results_dashboard.SendResults( |
| self.perf_data, |
| 'dummy_benchmark', |
| self.dashboard_url, |
| send_as_histograms=True, |
| token_generator_callback=self.dummy_token_generator, |
| num_retries=5) |
| |
| self.assertTrue(upload_result) |
| self.assertFalse(sleep_mock.mock_calls) |
| |
| # check token id is logged to info. |
| found_token = False |
| for log_call in log_mock.call_args_list: |
| log = log_call[0][0] % tuple(log_call[0][1:]) |
| if 'dummy1234' in log: |
| found_token = True |
| break |
| self.assertTrue( |
| found_token, msg='Upload completion token not found in logs.') |