예제 #1
0
def _MockFetch(url=None):
    if start_try_job._BISECT_CONFIG_PATH in url:
        return testing_common.FakeResponseObject(
            200, base64.encodestring(_BISECT_CONFIG_CONTENTS))
    elif start_try_job._PERF_CONFIG_PATH in url:
        return testing_common.FakeResponseObject(
            200, base64.encodestring(_PERF_CONFIG_CONTENTS))
 def _MockFetch(unused_url):  # pylint: disable=unused-argument
     response_text = _UNIT_JSON
     if malformed_json:
         response_text = 'this is not json'
     if base64_encoded:
         response_text = base64.b64encode(response_text)
     return testing_common.FakeResponseObject(status, response_text)
예제 #3
0
def _MockMakeRequest(path, *args, **kwargs):  # pylint: disable=unused-argument
    """Mocks out a request, returning a canned response."""
    if path.endswith('xsrf_token'):
        assert kwargs['headers']['X-Requesting-XSRF-Token'] == 1
        return testing_common.FakeResponseObject(200, _FAKE_XSRF_TOKEN)
    if path == 'upload':
        assert kwargs['method'] == 'POST'
        assert _EXPECTED_CONFIG_DIFF in kwargs['body'], (
            '%s\nnot in\n%s\n' % (_EXPECTED_CONFIG_DIFF, kwargs['body']))
        return testing_common.FakeResponseObject(200, _ISSUE_CREATED_RESPONSE)
    if path == '33001/upload_content/1/1001':
        assert kwargs['method'] == 'POST'
        assert _TEST_EXPECTED_CONFIG_CONTENTS in kwargs['body']
        return testing_common.FakeResponseObject(200, 'Dummy content')
    if path == '33001/upload_complete/1':
        assert kwargs['method'] == 'POST'
        return testing_common.FakeResponseObject(200, 'Dummy content')
    if path == '33001/try/1':
        assert _TEST_EXPECTED_BOT in kwargs['body']
        return testing_common.FakeResponseObject(200, 'Dummy content')
    assert False, 'Invalid url %s requested!' % path
예제 #4
0
def _MockFetch(url=None):
    url_to_response_map = {
        'http://src.chromium.org/viewvc/chrome?view=revision&revision=20798':
        [200, _REVISION_RESPONSE],
        'http://src.chromium.org/viewvc/chrome?view=revision&revision=20799':
        [200, 'REVISION REQUEST FAILED!'],
        'https://codereview.chromium.org/api/17504006':
        [200, json.dumps(json.loads(_ISSUE_RESPONSE))],
    }

    if url not in url_to_response_map:
        assert False, 'Bad url %s' % url

    response_code = url_to_response_map[url][0]
    response = url_to_response_map[url][1]
    return testing_common.FakeResponseObject(response_code, response)
예제 #5
0
class FileBugTest(testing_common.TestCase):
    def setUp(self):
        super(FileBugTest, self).setUp()
        app = webapp2.WSGIApplication([('/file_bug', file_bug.FileBugHandler)])
        self.testapp = webtest.TestApp(app)
        testing_common.SetSheriffDomains(['chromium.org'])
        testing_common.SetIsInternalUser('*****@*****.**', True)
        testing_common.SetIsInternalUser('*****@*****.**', False)
        self.SetCurrentUser('*****@*****.**')

        # Add a fake issue tracker service that we can get call values from.
        file_bug.issue_tracker_service = mock.MagicMock()
        self.original_service = file_bug.issue_tracker_service.IssueTrackerService
        self.service = MockIssueTrackerService
        file_bug.issue_tracker_service.IssueTrackerService = self.service

    def tearDown(self):
        super(FileBugTest, self).tearDown()
        file_bug.issue_tracker_service.IssueTrackerService = self.original_service
        self.UnsetCurrentUser()

    def _AddSampleAlerts(self):
        """Adds sample data and returns a dict of rev to anomaly key."""
        # Add sample sheriff, masters, bots, and tests.
        sheriff_key = sheriff.Sheriff(id='Sheriff').put()
        testing_common.AddTests(
            ['ChromiumPerf'], ['linux'],
            {'scrolling': {
                'first_paint': {},
                'mean_frame_time': {},
            }})
        test_key1 = utils.TestKey('ChromiumPerf/linux/scrolling/first_paint')
        test_key2 = utils.TestKey(
            'ChromiumPerf/linux/scrolling/mean_frame_time')
        anomaly_key1 = self._AddAnomaly(111995, 112005, test_key1, sheriff_key)
        anomaly_key2 = self._AddAnomaly(112000, 112010, test_key2, sheriff_key)
        return (anomaly_key1, anomaly_key2)

    def _AddAnomaly(self, start_rev, end_rev, test_key, sheriff_key):
        return anomaly.Anomaly(start_revision=start_rev,
                               end_revision=end_rev,
                               test=test_key,
                               median_before_anomaly=100,
                               median_after_anomaly=200,
                               sheriff=sheriff_key).put()

    def testGet_WithNoKeys_ShowsError(self):
        # When a request is made and no keys parameter is given,
        # an error message is shown in the reply.
        response = self.testapp.get(
            '/file_bug?summary=s&description=d&finish=true')
        self.assertIn('<div class="error">', response.body)
        self.assertIn('No alerts specified', response.body)

    def testGet_WithNoFinish_ShowsForm(self):
        # When a GET request is sent with keys specified but the finish parameter
        # is not given, the response should contain a form for the sheriff to fill
        # in bug details (summary, description, etc).
        alert_keys = self._AddSampleAlerts()
        response = self.testapp.get(
            '/file_bug?summary=s&description=d&keys=%s' %
            alert_keys[0].urlsafe())
        self.assertEqual(1, len(response.html('form')))

    def testInternalBugLabel(self):
        # If any of the alerts are marked as internal-only, which should happen
        # when the corresponding test is internal-only, then the create bug dialog
        # should suggest adding a Restrict-View-Google label.
        self.SetCurrentUser('*****@*****.**')
        alert_keys = self._AddSampleAlerts()
        anomaly_entity = alert_keys[0].get()
        anomaly_entity.internal_only = True
        anomaly_entity.put()
        response = self.testapp.get(
            '/file_bug?summary=s&description=d&keys=%s' %
            alert_keys[0].urlsafe())
        self.assertIn('Restrict-View-Google', response.body)

    def testGet_SetsBugLabelsComponents(self):
        self.SetCurrentUser('*****@*****.**')
        alert_keys = self._AddSampleAlerts()
        bug_label_patterns.AddBugLabelPattern('label1-foo',
                                              '*/*/*/first_paint')
        bug_label_patterns.AddBugLabelPattern('Cr-Performance-Blink',
                                              '*/*/*/mean_frame_time')
        response = self.testapp.get(
            '/file_bug?summary=s&description=d&keys=%s,%s' %
            (alert_keys[0].urlsafe(), alert_keys[1].urlsafe()))
        self.assertIn('label1-foo', response.body)
        self.assertIn('Performance&gt;Blink', response.body)

    @mock.patch(
        'google.appengine.api.app_identity.get_default_version_hostname',
        mock.MagicMock(return_value='chromeperf.appspot.com'))
    @mock.patch.object(file_bug.auto_bisect, 'StartNewBisectForBug',
                       mock.MagicMock(return_value={
                           'issue_id': 123,
                           'issue_url': 'foo.com'
                       }))
    def _PostSampleBug(self):
        alert_keys = self._AddSampleAlerts()
        response = self.testapp.post('/file_bug', [
            ('keys', '%s,%s' %
             (alert_keys[0].urlsafe(), alert_keys[1].urlsafe())),
            ('summary', 's'),
            ('description', 'd\n'),
            ('finish', 'true'),
            ('label', 'one'),
            ('label', 'two'),
            ('component', 'Foo>Bar'),
        ])
        return response

    @mock.patch.object(file_bug, '_GetAllCurrentVersionsFromOmahaProxy',
                       mock.MagicMock(return_value=[]))
    @mock.patch.object(file_bug.auto_bisect, 'StartNewBisectForBug',
                       mock.MagicMock(return_value={
                           'issue_id': 123,
                           'issue_url': 'foo.com'
                       }))
    def testGet_WithFinish_CreatesBug(self):
        # When a POST request is sent with keys specified and with the finish
        # parameter given, an issue will be created using the issue tracker
        # API, and the anomalies will be updated, and a response page will
        # be sent which indicates success.
        self.service.bug_id = 277761
        response = self._PostSampleBug()

        # The response page should have a bug number.
        self.assertIn('277761', response.body)

        # The anomaly entities should be updated.
        for anomaly_entity in anomaly.Anomaly.query().fetch():
            if anomaly_entity.end_revision in [112005, 112010]:
                self.assertEqual(277761, anomaly_entity.bug_id)
            else:
                self.assertIsNone(anomaly_entity.bug_id)

        # Two HTTP requests are made when filing a bug; only test 2nd request.
        comment = self.service.add_comment_args[1]
        self.assertIn(
            'https://chromeperf.appspot.com/group_report?bug_id=277761',
            comment)
        self.assertIn('https://chromeperf.appspot.com/group_report?keys=',
                      comment)
        self.assertIn(
            '\n\n\nBot(s) for this bug\'s original alert(s):\n\nlinux',
            comment)

    @mock.patch.object(file_bug, '_GetAllCurrentVersionsFromOmahaProxy',
                       mock.MagicMock(return_value=[{
                           'versions': [{
                               'branch_base_position': '112000',
                               'current_version': '2.0'
                           }, {
                               'branch_base_position': '111990',
                               'current_version': '1.0'
                           }]
                       }]))
    @mock.patch.object(file_bug.auto_bisect, 'StartNewBisectForBug',
                       mock.MagicMock(return_value={
                           'issue_id': 123,
                           'issue_url': 'foo.com'
                       }))
    def testGet_WithFinish_LabelsBugWithMilestone(self):
        # Here, we expect the bug to have the following start revisions:
        # [111995, 112005] and the milestones are M-1 for rev 111990 and
        # M-2 for 11200. Hence the expected behavior is to label the bug
        # M-2 since 111995 (lowest possible revision introducing regression)
        # is less than 112000 (revision for M-2).
        self._PostSampleBug()
        self.assertIn('M-2', self.service.new_bug_kwargs['labels'])

    @unittest.skip('Flaky; see #1555.')
    @mock.patch('google.appengine.api.urlfetch.fetch',
                mock.MagicMock(return_value=testing_common.FakeResponseObject(
                    200,
                    json.dumps([{
                        'versions': [{
                            'branch_base_position': '111999',
                            'current_version': '3.0.1234.32'
                        }, {
                            'branch_base_position': '112000',
                            'current_version': '2.0'
                        }, {
                            'branch_base_position': '111990',
                            'current_version': '1.0'
                        }]
                    }]))))
    def testGet_WithFinish_LabelsBugWithLowestMilestonePossible(self):
        # Here, we expect the bug to have the following start revisions:
        # [111995, 112005] and the milestones are M-1 for rev 111990, M-2
        # for 112000 and M-3 for 111999. Hence the expected behavior is to
        # label the bug M-2 since 111995 is less than 112000 (M-2) and 111999
        # (M-3) AND M-2 is lower than M-3.
        self._PostSampleBug()
        self.assertIn('M-2', self.service.new_bug_kwargs['labels'])

    @mock.patch('google.appengine.api.urlfetch.fetch',
                mock.MagicMock(
                    return_value=testing_common.FakeResponseObject(200, '[]')))
    def testGet_WithFinish_SucceedsWithNoVersions(self):
        # Here, we test that we don't label the bug with an unexpected value when
        # there is no version information from omahaproxy (for whatever reason)
        self._PostSampleBug()
        labels = self.service.new_bug_kwargs['labels']
        self.assertEqual(0, len([x for x in labels if x.startswith(u'M-')]))

    @mock.patch('google.appengine.api.urlfetch.fetch',
                mock.MagicMock(
                    return_value=testing_common.FakeResponseObject(200, '[]')))
    def testGet_WithFinish_SucceedsWithComponents(self):
        # Here, we test that components are posted separately from labels.
        self._PostSampleBug()
        self.assertIn('Foo>Bar', self.service.new_bug_kwargs['components'])

    @mock.patch('google.appengine.api.urlfetch.fetch',
                mock.MagicMock(return_value=testing_common.FakeResponseObject(
                    200,
                    json.dumps([{
                        'versions': [{
                            'branch_base_position': '0',
                            'current_version': '1.0'
                        }]
                    }]))))
    def testGet_WithFinish_SucceedsWithRevisionOutOfRange(self):
        # Here, we test that we label the bug with the highest milestone when the
        # revision introducing regression is beyond all milestones in the list.
        self._PostSampleBug()
        self.assertIn('M-1', self.service.new_bug_kwargs['labels'])

    @mock.patch('google.appengine.api.urlfetch.fetch',
                mock.MagicMock(return_value=testing_common.FakeResponseObject(
                    200,
                    json.dumps([{
                        'versions': [{
                            'branch_base_position': 'N/A',
                            'current_version': 'N/A'
                        }]
                    }]))))
    @mock.patch('logging.warn')
    def testGet_WithFinish_SucceedsWithNAAndLogsWarning(self, mock_warn):
        self._PostSampleBug()
        labels = self.service.new_bug_kwargs['labels']
        self.assertEqual(0, len([x for x in labels if x.startswith(u'M-')]))
        self.assertEqual(1, mock_warn.call_count)
예제 #6
0
class EmailSheriffTest(testing_common.TestCase):
    def _AddTestToStubDataStore(self):
        """Adds a test which will be used in the methods below."""
        bug_label_patterns.AddBugLabelPattern('label1', '*/*/dromaeo/dom')
        bug_label_patterns.AddBugLabelPattern('label2', '*/*/other/test')
        testing_common.AddTests(['ChromiumPerf'], ['Win7'],
                                {'dromaeo': {
                                    'dom': {}
                                }})
        test = utils.TestKey('ChromiumPerf/Win7/dromaeo/dom').get()
        test.improvement_direction = anomaly.DOWN
        sheriff.Sheriff(id='Chromium Perf Sheriff',
                        url=_SHERIFF_URL,
                        email=_SHERIFF_EMAIL).put()
        return test

    def _GetDefaultMailArgs(self):
        """Adds an Anomaly and returns arguments for email_sheriff.EmailSheriff."""
        test_entity = self._AddTestToStubDataStore()
        sheriff_entity = ndb.Key('Sheriff', 'Chromium Perf Sheriff').get()
        anomaly_entity = anomaly.Anomaly(
            median_before_anomaly=5.0,
            median_after_anomaly=10.0,
            start_revision=10002,
            end_revision=10004,
            sheriff=sheriff_entity.key,
            test=utils.TestKey('ChromiumPerf/Win7/dromaeo/dom'))
        return {
            'sheriff': sheriff_entity,
            'test': test_entity,
            'anomaly': anomaly_entity
        }

    @mock.patch('google.appengine.api.urlfetch.fetch',
                mock.MagicMock(return_value=testing_common.FakeResponseObject(
                    200, 'document.write(\'sullivan\')')))
    def testEmailSheriff_ContentAndRecipientAreCorrect(self):
        email_sheriff.EmailSheriff(**self._GetDefaultMailArgs())

        messages = self.mail_stub.get_sent_messages()
        self.assertEqual(1, len(messages))
        self.assertEqual('*****@*****.**', messages[0].sender)
        self.assertEqual('[email protected],[email protected]',
                         messages[0].to)

        name = 'dromaeo/dom on Win7'
        expected_subject = '100.0%% regression in %s at 10002:10004' % name
        self.assertEqual(expected_subject, messages[0].subject)
        body = str(messages[0].body)
        self.assertIn('10002 - 10004', body)
        self.assertIn('100.0%', body)
        self.assertIn('ChromiumPerf', body)
        self.assertIn('Win7', body)
        self.assertIn('dromaeo/dom', body)

        html = str(messages[0].html)
        self.assertIn('<b>10002 - 10004</b>', html)
        self.assertIn('<b>100.0%</b>', html)
        self.assertIn('<b>ChromiumPerf</b>', html)
        self.assertIn('<b>Win7</b>', html)
        self.assertIn('<b>dromaeo/dom</b>', html)

        # Bug links
        self.assertIn(urllib.quote(expected_subject), body)
        self.assertIn(
            'labels=Type-Bug-Regression,Pri-2,Performance-Sheriff,label1',
            html)
        # Sheriff link
        self.assertIn(
            '/alerts?sheriff=%s' % urllib.quote('Chromium Perf Sheriff'), html)

    @mock.patch('google.appengine.api.urlfetch.fetch',
                mock.MagicMock(return_value=testing_common.FakeResponseObject(
                    200, 'document.write(\'sonnyrao, digit\')')))
    def testEmailSheriff_MultipleSheriffs_AllGetEmailed(self):
        email_sheriff.EmailSheriff(**self._GetDefaultMailArgs())
        messages = self.mail_stub.get_sent_messages()
        self.assertEqual(1, len(messages))
        self.assertEqual('*****@*****.**', messages[0].sender)
        self.assertEqual(
            '[email protected],[email protected],[email protected]',
            messages[0].to)

    def testEmail_NoSheriffUrl_EmailSentToSheriffRotationEmailAddress(self):
        args = self._GetDefaultMailArgs()
        args['sheriff'].url = None
        email_sheriff.EmailSheriff(**args)
        messages = self.mail_stub.get_sent_messages()
        self.assertEqual(1, len(messages))
        # An email is only sent to the general sheriff rotation email;
        # There is no other specific sheriff to send it to.
        self.assertEqual('*****@*****.**', messages[0].to)

    @mock.patch(
        'google.appengine.api.urlfetch.fetch',
        mock.MagicMock(
            return_value=testing_common.FakeResponseObject(200, 'garbage')))
    def testEmailSheriff_RotationUrlHasInvalidContent_EmailStillSent(self):
        """Tests the email to list when the rotation URL returns garbage."""
        args = self._GetDefaultMailArgs()
        email_sheriff.EmailSheriff(**args)
        messages = self.mail_stub.get_sent_messages()
        self.assertEqual(1, len(messages))
        # An email is only sent to the general sheriff rotation email.
        self.assertEqual('*****@*****.**', messages[0].to)

    def testEmailSheriff_PercentChangeMaxFloat_ContentSaysAlertSize(self):
        """Tests the email content for "freakin huge" alert."""
        args = self._GetDefaultMailArgs()
        args['sheriff'].url = None
        args['anomaly'].median_before_anomaly = 0.0
        email_sheriff.EmailSheriff(**args)
        messages = self.mail_stub.get_sent_messages()
        self.assertEqual(1, len(messages))
        self.assertIn(anomaly.FREAKIN_HUGE, str(messages[0].subject))
        self.assertNotIn(str(sys.float_info.max), str(messages[0].body))
        self.assertIn(anomaly.FREAKIN_HUGE, str(messages[0].body))
        self.assertNotIn(str(sys.float_info.max), str(messages[0].html))
        self.assertIn(anomaly.FREAKIN_HUGE, str(messages[0].html))
예제 #7
0
def _MockFailedFetch(url=None):  # pylint: disable=unused-argument
    return testing_common.FakeResponseObject(404, {})
예제 #8
0
class AssociateAlertsTest(testing_common.TestCase):
    def setUp(self):
        super(AssociateAlertsTest, self).setUp()
        app = webapp2.WSGIApplication([
            ('/associate_alerts', associate_alerts.AssociateAlertsHandler)
        ])
        self.testapp = webtest.TestApp(app)
        testing_common.SetSheriffDomains(['chromium.org'])
        self.SetCurrentUser('*****@*****.**', is_admin=True)

    def _AddSheriff(self):
        """Adds a Sheriff and returns its key."""
        return sheriff.Sheriff(id='Chromium Perf Sheriff',
                               email='*****@*****.**').put()

    def _AddTests(self):
        """Adds sample Tests and returns a list of their keys."""
        testing_common.AddTests(['ChromiumGPU'], ['linux-release'], {
            'scrolling-benchmark': {
                'first_paint': {},
                'mean_frame_time': {},
            }
        })
        return map(utils.TestKey, [
            'ChromiumGPU/linux-release/scrolling-benchmark/first_paint',
            'ChromiumGPU/linux-release/scrolling-benchmark/mean_frame_time',
        ])

    def _AddAnomalies(self):
        """Adds sample Anomaly data and returns a dict of revision to key."""
        sheriff_key = self._AddSheriff()
        test_keys = self._AddTests()
        key_map = {}

        # Add anomalies to the two tests alternately.
        for end_rev in range(10000, 10120, 10):
            test_key = test_keys[0] if end_rev % 20 == 0 else test_keys[1]
            anomaly_key = anomaly.Anomaly(start_revision=(end_rev - 5),
                                          end_revision=end_rev,
                                          test=test_key,
                                          median_before_anomaly=100,
                                          median_after_anomaly=200,
                                          sheriff=sheriff_key).put()
            key_map[end_rev] = anomaly_key.urlsafe()

        # Add an anomaly that overlaps.
        anomaly_key = anomaly.Anomaly(start_revision=9990,
                                      end_revision=9996,
                                      test=test_keys[0],
                                      median_before_anomaly=100,
                                      median_after_anomaly=200,
                                      sheriff=sheriff_key).put()
        key_map[9996] = anomaly_key.urlsafe()

        # Add an anomaly that overlaps and has bug ID.
        anomaly_key = anomaly.Anomaly(start_revision=9990,
                                      end_revision=9997,
                                      test=test_keys[0],
                                      median_before_anomaly=100,
                                      median_after_anomaly=200,
                                      sheriff=sheriff_key,
                                      bug_id=12345).put()
        key_map[9997] = anomaly_key.urlsafe()
        return key_map

    def testGet_NoKeys_ShowsError(self):
        response = self.testapp.get('/associate_alerts')
        self.assertIn('<div class="error">', response.body)

    def testGet_SameAsPost(self):
        get_response = self.testapp.get('/associate_alerts')
        post_response = self.testapp.post('/associate_alerts')
        self.assertEqual(get_response.body, post_response.body)

    def testGet_InvalidBugId_ShowsError(self):
        key_map = self._AddAnomalies()
        response = self.testapp.get('/associate_alerts?keys=%s&bug_id=foo' %
                                    key_map[9996])
        self.assertIn('<div class="error">', response.body)
        self.assertIn('Invalid bug ID', response.body)

    # In this test method, the request handler is expected to use urlfetch.fetch
    # to request recent bug information. Below is some sample data in the format
    # returned by this request.
    @mock.patch('google.appengine.api.urlfetch.fetch',
                mock.MagicMock(return_value=testing_common.FakeResponseObject(
                    200,
                    json.dumps({
                        'items': [
                            {
                                'id': 12345,
                                'summary':
                                '5% regression in bot/suite/x at 10000:20000',
                                'state': 'open',
                                'status': 'New',
                                'author': {
                                    'name': '*****@*****.**'
                                },
                            },
                            {
                                'id': 13579,
                                'summary':
                                '1% regression in bot/suite/y at 10000:20000',
                                'state': 'closed',
                                'status': 'WontFix',
                                'author': {
                                    'name': '*****@*****.**'
                                },
                            },
                        ]
                    }))))
    def testGet_NoBugId_ShowsDialog(self):
        # When a GET request is made with some anomaly keys but no bug ID,
        # A HTML form is shown for the user to input a bug number.
        key_map = self._AddAnomalies()
        response = self.testapp.get('/associate_alerts?keys=%s' %
                                    key_map[10000])
        # The response contains a table of recent bugs and a form.
        self.assertIn('12345', response.body)
        self.assertIn('13579', response.body)
        self.assertIn('<form', response.body)

    def testGet_WithBugId_AlertIsAssociatedWithBugId(self):
        # When the bug ID is given and the alerts overlap, then the Anomaly
        # entities are updated and there is a resopnse indicating success.
        key_map = self._AddAnomalies()
        response = self.testapp.get(
            '/associate_alerts?keys=%s,%s&bug_id=12345' %
            (key_map[9996], key_map[10000]))
        # The response page should have a bug number.
        self.assertIn('12345', response.body)
        # The Anomaly entities should be updated.
        for anomaly_entity in anomaly.Anomaly.query().fetch():
            if anomaly_entity.end_revision in (10000, 9996):
                self.assertEqual(12345, anomaly_entity.bug_id)
            elif anomaly_entity.end_revision != 9997:
                self.assertIsNone(anomaly_entity.bug_id)

    def testGet_WithStoppageAlert_ChangesAlertBugId(self):
        test_keys = self._AddTests()
        rows = testing_common.AddRows(utils.TestPath(test_keys[0]), {10, 20})
        alert_key = stoppage_alert.CreateStoppageAlert(test_keys[0].get(),
                                                       rows[0]).put()
        self.testapp.get('/associate_alerts?bug_id=123&keys=%s' %
                         alert_key.urlsafe())
        self.assertEqual(123, alert_key.get().bug_id)

    def testGet_TargetBugHasNoAlerts_DoesNotAskForConfirmation(self):
        # Associating alert with bug ID that has no alerts is always OK.
        key_map = self._AddAnomalies()
        response = self.testapp.get('/associate_alerts?keys=%s,%s&bug_id=578' %
                                    (key_map[9996], key_map[10000]))
        # The response page should have a bug number.
        self.assertIn('578', response.body)
        # The Anomaly entities should be updated.
        self.assertEqual(
            578,
            anomaly.Anomaly.query(
                anomaly.Anomaly.end_revision == 9996).get().bug_id)
        self.assertEqual(
            578,
            anomaly.Anomaly.query(
                anomaly.Anomaly.end_revision == 10000).get().bug_id)

    def testGet_NonOverlappingAlerts_AsksForConfirmation(self):
        # Associating alert with bug ID that contains non-overlapping revision
        # ranges should show a confirmation page.
        key_map = self._AddAnomalies()
        response = self.testapp.get(
            '/associate_alerts?keys=%s,%s&bug_id=12345' %
            (key_map[10000], key_map[10010]))
        # The response page should show confirmation page.
        self.assertIn('Do you want to continue?', response.body)
        # The Anomaly entities should not be updated.
        for anomaly_entity in anomaly.Anomaly.query().fetch():
            if anomaly_entity.end_revision != 9997:
                self.assertIsNone(anomaly_entity.bug_id)

    def testGet_WithConfirm_AssociatesWithNewBugId(self):
        # Associating alert with bug ID and with confirmed non-overlapping revision
        # range should update alert with bug ID.
        key_map = self._AddAnomalies()
        response = self.testapp.get(
            '/associate_alerts?confirm=true&keys=%s,%s&bug_id=12345' %
            (key_map[10000], key_map[10010]))
        # The response page should have the bug number.
        self.assertIn('12345', response.body)
        # The Anomaly entities should be updated.
        for anomaly_entity in anomaly.Anomaly.query().fetch():
            if anomaly_entity.end_revision in (10000, 10010):
                self.assertEqual(12345, anomaly_entity.bug_id)
            elif anomaly_entity.end_revision != 9997:
                self.assertIsNone(anomaly_entity.bug_id)

    def testRevisionRangeFromSummary(self):
        # If the summary is in the expected format, a pair is returned.
        self.assertEqual(
            (10000, 10500),
            associate_alerts._RevisionRangeFromSummary(
                '1% regression in bot/my_suite/test at 10000:10500'))
        # Otherwise None is returned.
        self.assertIsNone(
            associate_alerts._RevisionRangeFromSummary(
                'Regression in rev ranges 12345 to 20000'))

    def testRangesOverlap_NonOverlapping_ReturnsFalse(self):
        self.assertFalse(associate_alerts._RangesOverlap((1, 5), (6, 9)))
        self.assertFalse(associate_alerts._RangesOverlap((6, 9), (1, 5)))

    def testRangesOverlap_NoneGiven_ReturnsFalse(self):
        self.assertFalse(associate_alerts._RangesOverlap((1, 5), None))
        self.assertFalse(associate_alerts._RangesOverlap(None, (1, 5)))
        self.assertFalse(associate_alerts._RangesOverlap(None, None))

    def testRangesOverlap_OneIncludesOther_ReturnsTrue(self):
        # True if one range envelopes the other.
        self.assertTrue(associate_alerts._RangesOverlap((1, 9), (2, 5)))
        self.assertTrue(associate_alerts._RangesOverlap((2, 5), (1, 9)))

    def testRangesOverlap_PartlyOverlap_ReturnsTrue(self):
        self.assertTrue(associate_alerts._RangesOverlap((1, 6), (5, 9)))
        self.assertTrue(associate_alerts._RangesOverlap((5, 9), (1, 6)))

    def testRangesOverlap_CommonBoundary_ReturnsTrue(self):
        self.assertTrue(associate_alerts._RangesOverlap((1, 6), (6, 9)))
        self.assertTrue(associate_alerts._RangesOverlap((6, 9), (1, 6)))
예제 #9
0
 def _MockFetch(_):
     response_text = json.dumps({'key': 'this is well-formed JSON.'})
     if base64_encoded:
         response_text = base64.b64encode(response_text)
     return testing_common.FakeResponseObject(status, response_text)
예제 #10
0
def _MockFetch(url=None):
    url_to_response_map = {
        'https://test-rietveld.appspot.com/api/200034/1': [
            200,
            json.dumps({
                'try_job_results': [{
                    'result': '0',
                    'builder': 'win_perf_bisect',
                    'url': 'http://build.chromium.org/508'
                }]
            })
        ],
        'https://test-rietveld.appspot.com/api/302304/1': [
            200,
            json.dumps({
                'try_job_results': [{
                    'result': '2',
                    'builder': 'win_perf_bisect',
                    'url': 'http://build.chromium.org/509'
                }]
            })
        ],
        'https://test-rietveld.appspot.com/api/100001/1': [
            200,
            json.dumps({
                'try_job_results': [{
                    'result': '6',
                    'builder': 'win_perf_bisect',
                    'url': 'http://build.chromium.org/510'
                }]
            })
        ],
        'https://test-rietveld.appspot.com/api/200035/1': [
            200,
            json.dumps({
                'try_job_results': [{
                    'result': '0',
                    'builder': 'win_perf_bisect',
                    'url': 'http://build.chromium.org/511'
                }]
            })
        ],
        'https://test-rietveld.appspot.com/api/200036/1': [
            200,
            json.dumps({
                'try_job_results': [{
                    'result': '0',
                    'builder': 'win_perf_bisect',
                    'url': 'http://build.chromium.org/512'
                }]
            })
        ],
        'https://test-rietveld.appspot.com/api/200037/1': [
            200,
            json.dumps({
                'try_job_results': [{
                    'result': '0',
                    'builder': 'win_perf_bisect',
                    'url': 'http://build.chromium.org/513'
                }]
            })
        ],
        'https://test-rietveld.appspot.com/api/200038/1': [
            200,
            json.dumps({
                'try_job_results': [{
                    'result': '0',
                    'builder': 'win_perf_bisect',
                    'url': 'http://build.chromium.org/514'
                }]
            })
        ],
        'https://test-rietveld.appspot.com/api/200039/1': [
            200,
            json.dumps({
                'try_job_results': [{
                    'result':
                    '0',
                    'builder':
                    'win_perf_bisect',
                    'url':
                    'http://build.chromium.org/builders/515'
                }]
            })
        ],
        'http://build.chromium.org/json/builders/515': [
            200,
            json.dumps({
                'steps': [{
                    'name': 'Working on abc',
                    'results': [0]
                }, {
                    'name': 'Working on def',
                    'results': [2]
                }],
                'times': [1411501756.293642, 1411545237.89049],
                'text': ['failed', 'slave_steps', 'failed', 'Working on def']
            })
        ],
        'http://build.chromium.org/bb1234567/steps/Results/logs/stdio/text':
        [200, _BISECT_LOG_SINGLE_OWNER],
        'http://build.chromium.org/bb66666': [
            200,
            json.dumps({
                'steps': [{
                    'name': 'Working on abc',
                    'results': [0]
                }, {
                    'name': 'Working on def',
                    'results': [2]
                }],
                'times': [1411501756.293642, 1411545237.89049],
                'text': ['failed', 'slave_steps', 'failed', 'Working on def']
            })
        ],
        ('http://build.chromium.org/builders/bb66666'
         '/steps/Results/logs/stdio/text'): [404, ''],
        'http://build.chromium.org/json/builders/516':
        [200,
         json.dumps({'steps': [{
             'name': 'gclient',
             'results': [2]
         }]})],
        'http://src.chromium.org/viewvc/chrome?view=revision&revision=20798':
        [200, _REVISION_RESPONSE],
        'http://src.chromium.org/viewvc/chrome?view=revision&revision=20799':
        [200, 'REVISION REQUEST FAILED!'],
        'https://codereview.chromium.org/api/17504006':
        [200, json.dumps(json.loads(_ISSUE_RESPONSE))],
        'http://build.chromium.org/508/steps/Results/logs/stdio/text':
        [200, '===== BISECT JOB RESULTS ====='],
        'http://build.chromium.org/509/steps/Results/logs/stdio/text':
        [200, 'BISECT FAILURE! '],
        'http://build.chromium.org/511/steps/Results/logs/stdio/text':
        [200, _BISECT_LOG_MULTI_OWNER],
        'http://build.chromium.org/512/steps/Results/logs/stdio/text':
        [200, _BISECT_LOG_MULTI_SAME_OWNER],
        'http://build.chromium.org/513/steps/Results/logs/stdio/text':
        [200, _BISECT_LOG_SINGLE_OWNER],
        'http://build.chromium.org/514/steps/Results/logs/stdio/text':
        [200, _BISECT_LOG_FAILED_REVISION],
        'http://build.chromium.org/builders/515/steps/Results/logs/stdio/text':
        [404, ''],
        'http://build.chromium.org/builders/515/steps/Working%20on%20abc/logs/'
        'stdio/text': [200, _BISECT_LOG_PARTIAL_RESULT],
        'http://build.chromium.org/builders/516/steps/slave_steps/logs/stdio/'
        'text': [200, _BISECT_LOG_INFRA_FAILURE],
        'http://build.chromium.org/508/steps/Running%20Bisection/logs/stdio/'
        'text': [200, _PERF_LOG_WITH_RESULTS],
        'http://build.chromium.org/511/steps/Running%20Bisection/logs/stdio/'
        'text': [200, ''],
    }

    if url not in url_to_response_map:
        assert False, 'Bad url %s' % url

    response_code = url_to_response_map[url][0]
    response = url_to_response_map[url][1]
    return testing_common.FakeResponseObject(response_code, response)
예제 #11
0
class MainTest(testing_common.TestCase):
    def setUp(self):
        super(MainTest, self).setUp()
        app = webapp2.WSGIApplication([('/', main.MainHandler)])
        self.testapp = webtest.TestApp(app)

    @mock.patch(
        'google.appengine.api.urlfetch.fetch',
        mock.MagicMock(return_value=testing_common.FakeResponseObject(500, ''))
    )
    def testGet_BugRequestFails_PageIsStillShown(self):
        # Even if the recent bugs list can't be fetched, the page should load.
        response = self.testapp.get('/')
        self.assertIn('<html>', response.body)

    def testGetColorClass(self):
        self.assertEqual('over-50', main._GetColorClass(95))
        self.assertEqual('over-40', main._GetColorClass(45))
        self.assertEqual('over-30', main._GetColorClass(31))
        self.assertEqual('over-20', main._GetColorClass(30))
        self.assertEqual('over-10', main._GetColorClass(12.0))
        self.assertEqual('under-10', main._GetColorClass(0.1))

    def testGetTopBugsResult_DeadlineExceededError_ReturnsEmptyList(self):
        mock_rpc = mock.MagicMock()
        mock_rpc.get_result = mock.MagicMock(
            side_effect=urlfetch_errors.DeadlineExceededError)
        self.assertEqual([], main._GetTopBugsResult(mock_rpc))

    def testGetTopBugsResult_DownloadError_ReturnsEmptyList(self):
        mock_rpc = mock.MagicMock()
        mock_rpc.get_result = mock.MagicMock(
            side_effect=urlfetch.DownloadError)
        self.assertEqual([], main._GetTopBugsResult(mock_rpc))

    def testAnomalyInfoDicts(self):
        testing_common.AddTests(['M'], ['b'], {'t': {'foo': {}}})
        foo_key = utils.TestKey('M/b/t/foo')
        foo_anomaly = anomaly.Anomaly(start_revision=14999,
                                      end_revision=15000,
                                      test=foo_key,
                                      bug_id=12345,
                                      median_before_anomaly=100,
                                      median_after_anomaly=200)
        anomaly_key = foo_anomaly.put()
        self.assertEqual([{
            'master':
            'M',
            'bot':
            'b',
            'testsuite':
            't',
            'test':
            'foo',
            'bug_id':
            12345,
            'start_revision':
            14999,
            'end_revision':
            15000,
            'key':
            anomaly_key.urlsafe(),
            'dashboard_link':
            ('https://chromeperf.appspot.com'
             '/group_report?keys=%s' % anomaly_key.urlsafe()),
            'percent_changed':
            '100.0%',
            'color_class':
            'over-50',
            'improvement':
            False,
        }], main._AnomalyInfoDicts([foo_anomaly], {foo_key: foo_key.get()}))

    def testAnomalyInfoDicts_MissingTest_AnomalySkipped(self):
        testing_common.AddTests(['M'], ['b'], {'t': {'foo': {}}})
        foo_key = utils.TestKey('M/b/t/foo')
        foo_anomaly = anomaly.Anomaly(start_revision=14999,
                                      end_revision=15000,
                                      test=foo_key,
                                      bug_id=12345,
                                      median_before_anomaly=100,
                                      median_after_anomaly=200)
        foo_anomaly.put()
        self.assertEqual([], main._AnomalyInfoDicts([foo_anomaly], {}))