| OLD | NEW |
| 1 # Copyright 2017 The Chromium Authors. All rights reserved. | 1 # Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import json | 5 import json |
| 6 | 6 |
| 7 import mock | 7 import mock |
| 8 import webapp2 | 8 import webapp2 |
| 9 import webtest | 9 import webtest |
| 10 | 10 |
| 11 from google.appengine.api import users | 11 from google.appengine.api import users |
| 12 | 12 |
| 13 from dashboard.api import api_auth | 13 from dashboard.api import api_auth |
| 14 from dashboard.common import namespaced_stored_object | 14 from dashboard.common import namespaced_stored_object |
| 15 from dashboard.common import testing_common | 15 from dashboard.common import testing_common |
| 16 from dashboard.common import utils | 16 from dashboard.common import utils |
| 17 from dashboard.services import gitiles_service | 17 from dashboard.services import gitiles_service |
| 18 from dashboard.pinpoint.handlers import new | 18 from dashboard.pinpoint.handlers import new |
| 19 from dashboard.pinpoint.models import job as job_module | 19 from dashboard.pinpoint.models import job as job_module |
| 20 | 20 |
| 21 AUTHORIZED_USER = users.User(email='authorized_person@chromium.org', | 21 |
| 22 _auth_domain='google.com') | 22 _AUTHORIZED_USER = users.User(email='authorized_person@chromium.org', |
| 23 UNAUTHORIZED_USER = users.User(email='foo@bar.com', _auth_domain='bar.com') | 23 _auth_domain='google.com') |
| 24 _UNAUTHORIZED_USER = users.User(email='foo@bar.com', _auth_domain='bar.com') |
| 25 |
| 26 |
| 27 _BASE_REQUEST = { |
| 28 'target': 'telemetry_perf_tests', |
| 29 'configuration': 'chromium-rel-mac11-pro', |
| 30 'benchmark': 'speedometer', |
| 31 'auto_explore': '1', |
| 32 'bug_id': '12345', |
| 33 'start_repository': 'src', |
| 34 'start_git_hash': '1', |
| 35 'end_repository': 'src', |
| 36 'end_git_hash': '3', |
| 37 } |
| 24 | 38 |
| 25 | 39 |
| 26 class NewTest(testing_common.TestCase): | 40 class NewTest(testing_common.TestCase): |
| 27 | 41 |
| 28 def setUp(self): | 42 def setUp(self): |
| 29 super(NewTest, self).setUp() | 43 super(NewTest, self).setUp() |
| 30 | 44 |
| 31 app = webapp2.WSGIApplication([ | 45 app = webapp2.WSGIApplication([ |
| 32 webapp2.Route(r'/api/new', new.New), | 46 webapp2.Route(r'/api/new', new.New), |
| 33 ]) | 47 ]) |
| 34 self.testapp = webtest.TestApp(app) | 48 self.testapp = webtest.TestApp(app) |
| 35 | 49 |
| 36 self.SetCurrentUser('internal@chromium.org', is_admin=True) | 50 self.SetCurrentUser('internal@chromium.org', is_admin=True) |
| 37 | 51 |
| 38 namespaced_stored_object.Set('repositories', { | 52 namespaced_stored_object.Set('repositories', { |
| 39 'catapult': {'repository_url': 'http://catapult'}, | 53 'catapult': {'repository_url': 'http://catapult'}, |
| 40 'src': {'repository_url': 'http://src'}, | 54 'src': {'repository_url': 'http://src'}, |
| 41 }) | 55 }) |
| 42 | 56 |
| 43 def _SetAuthorizedOAuth(self, mock_oauth): | 57 def _SetAuthorizedOAuth(self, mock_oauth): |
| 44 mock_oauth.get_current_user.return_value = AUTHORIZED_USER | 58 mock_oauth.get_current_user.return_value = _AUTHORIZED_USER |
| 45 mock_oauth.get_client_id.return_value = ( | 59 mock_oauth.get_client_id.return_value = ( |
| 46 api_auth.OAUTH_CLIENT_ID_WHITELIST[0]) | 60 api_auth.OAUTH_CLIENT_ID_WHITELIST[0]) |
| 47 | 61 |
| 48 @mock.patch.object(utils, 'IsGroupMember', mock.MagicMock(return_value=False)) | 62 @mock.patch.object(utils, 'IsGroupMember', mock.MagicMock(return_value=False)) |
| 49 @mock.patch.object(api_auth, 'oauth') | 63 @mock.patch.object(api_auth, 'oauth') |
| 50 def testPost_NoAccess_ShowsError(self, mock_oauth): | 64 def testPost_NoAccess_ShowsError(self, mock_oauth): |
| 51 self.SetCurrentUser('external@chromium.org') | 65 self.SetCurrentUser('external@chromium.org') |
| 52 mock_oauth.get_current_user.return_value = UNAUTHORIZED_USER | 66 mock_oauth.get_current_user.return_value = _UNAUTHORIZED_USER |
| 53 mock_oauth.get_client_id.return_value = ( | 67 mock_oauth.get_client_id.return_value = ( |
| 54 api_auth.OAUTH_CLIENT_ID_WHITELIST[0]) | 68 api_auth.OAUTH_CLIENT_ID_WHITELIST[0]) |
| 55 response = self.testapp.post('/api/new', status=200) | 69 response = self.testapp.post('/api/new', status=200) |
| 56 self.assertIn('error', json.loads(response.body)) | 70 self.assertIn('error', json.loads(response.body)) |
| 57 | 71 |
| 58 @mock.patch.object(api_auth, 'oauth') | 72 @mock.patch.object(api_auth, 'oauth') |
| 59 @mock.patch.object(api_auth, 'users') | 73 @mock.patch.object(api_auth, 'users') |
| 60 def testPost_NoOauthUser(self, mock_users, mock_oauth): | 74 def testPost_NoOauthUser(self, mock_users, mock_oauth): |
| 61 mock_users.get_current_user.return_value = None | 75 mock_users.get_current_user.return_value = None |
| 62 mock_oauth.get_current_user.return_value = None | 76 mock_oauth.get_current_user.return_value = None |
| 63 mock_oauth.get_client_id.return_value = ( | 77 mock_oauth.get_client_id.return_value = ( |
| 64 api_auth.OAUTH_CLIENT_ID_WHITELIST[0]) | 78 api_auth.OAUTH_CLIENT_ID_WHITELIST[0]) |
| 65 response = self.testapp.post('/api/new', status=200) | 79 response = self.testapp.post('/api/new', status=200) |
| 66 self.assertIn('error', json.loads(response.body)) | 80 self.assertIn('error', json.loads(response.body)) |
| 67 | 81 |
| 68 @mock.patch.object(api_auth, 'oauth') | 82 @mock.patch.object(api_auth, 'oauth') |
| 69 @mock.patch.object(api_auth, 'users') | 83 @mock.patch.object(api_auth, 'users') |
| 70 def testPost_BadOauthClientId(self, mock_users, mock_oauth): | 84 def testPost_BadOauthClientId(self, mock_users, mock_oauth): |
| 71 mock_users.get_current_user.return_value = None | 85 mock_users.get_current_user.return_value = None |
| 72 mock_oauth.get_current_user.return_value = AUTHORIZED_USER | 86 mock_oauth.get_current_user.return_value = _AUTHORIZED_USER |
| 73 mock_oauth.get_client_id.return_value = 'invalid' | 87 mock_oauth.get_client_id.return_value = 'invalid' |
| 74 response = self.testapp.post('/api/new', status=200) | 88 response = self.testapp.post('/api/new', status=200) |
| 75 self.assertIn('error', json.loads(response.body)) | 89 self.assertIn('error', json.loads(response.body)) |
| 76 | 90 |
| 77 @mock.patch( | 91 @mock.patch( |
| 78 'dashboard.services.issue_tracker_service.IssueTrackerService', | 92 'dashboard.services.issue_tracker_service.IssueTrackerService', |
| 79 mock.MagicMock()) | 93 mock.MagicMock()) |
| 80 @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) | 94 @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) |
| 81 @mock.patch.object(gitiles_service, 'CommitInfo', mock.MagicMock()) | 95 @mock.patch.object(gitiles_service, 'CommitInfo', mock.MagicMock()) |
| 82 @mock.patch.object(gitiles_service, 'CommitRange') | 96 @mock.patch.object(gitiles_service, 'CommitRange') |
| 83 def testPost(self, mock_commit_range): | 97 def testPost(self, mock_commit_range): |
| 84 mock_commit_range.return_value = [ | 98 mock_commit_range.return_value = [ |
| 85 {'commit': '1'}, | 99 {'commit': '1'}, |
| 86 {'commit': '2'}, | 100 {'commit': '2'}, |
| 87 {'commit': '3'}, | 101 {'commit': '3'}, |
| 88 ] | 102 ] |
| 89 params = { | 103 response = self.testapp.post('/api/new', _BASE_REQUEST, status=200) |
| 90 'configuration': 'chromium-rel-mac11-pro', | |
| 91 'test_suite': 'speedometer', | |
| 92 'test': '', | |
| 93 'metric': 'Total', | |
| 94 'auto_explore': '1', | |
| 95 'bug_id': 12345, | |
| 96 'start_repository': 'src', | |
| 97 'start_git_hash': '1', | |
| 98 'end_repository': 'src', | |
| 99 'end_git_hash': '3' | |
| 100 } | |
| 101 response = self.testapp.post('/api/new', params, status=200) | |
| 102 result = json.loads(response.body) | 104 result = json.loads(response.body) |
| 103 self.assertIn('jobId', result) | 105 self.assertIn('jobId', result) |
| 104 self.assertEqual( | 106 self.assertEqual( |
| 105 result['jobUrl'], | 107 result['jobUrl'], |
| 106 'https://testbed.example.com/job/%s' % result['jobId']) | 108 'https://testbed.example.com/job/%s' % result['jobId']) |
| 107 | 109 |
| 108 def testPost_MetricButNoTestSuite(self): | 110 def testPost_MissingTarget(self): |
| 109 params = { | 111 request = dict(_BASE_REQUEST) |
| 110 'configuration': 'chromium-rel-mac11-pro', | 112 del request['target'] |
| 111 'test_suite': '', | 113 response = self.testapp.post('/api/new', request, status=200) |
| 112 'test': '', | 114 self.assertIn('error', json.loads(response.body)) |
| 113 'metric': 'Total', | 115 |
| 114 'auto_explore': '1', | 116 def testPost_InvalidTestConfig(self): |
| 115 'bug_id': 12345, | 117 request = dict(_BASE_REQUEST) |
| 116 'start_repository': 'src', | 118 del request['configuration'] |
| 117 'start_git_hash': '1', | 119 response = self.testapp.post('/api/new', request, status=200) |
| 118 'end_repository': 'src', | 120 self.assertIn('error', json.loads(response.body)) |
| 119 'end_git_hash': '3' | |
| 120 } | |
| 121 response = self.testapp.post('/api/new', params, status=200) | |
| 122 self.assertEqual({'error': new._ERROR_METRIC_NO_TEST_SUITE}, | |
| 123 json.loads(response.body)) | |
| 124 | 121 |
| 125 @mock.patch.object( | 122 @mock.patch.object( |
| 126 gitiles_service, 'CommitInfo', | 123 gitiles_service, 'CommitInfo', |
| 127 mock.MagicMock(side_effect=gitiles_service.NotFoundError)) | 124 mock.MagicMock(side_effect=gitiles_service.NotFoundError('message'))) |
| 128 def testPost_InvalidChange(self): | 125 def testPost_InvalidChange(self): |
| 129 params = { | 126 response = self.testapp.post('/api/new', _BASE_REQUEST, status=200) |
| 130 'configuration': 'chromium-rel-mac11-pro', | 127 self.assertEqual({'error': 'message'}, json.loads(response.body)) |
| 131 'test_suite': 'speedometer', | |
| 132 'test': '', | |
| 133 'metric': 'Total', | |
| 134 'auto_explore': '1', | |
| 135 'bug_id': 12345, | |
| 136 'start_repository': 'src', | |
| 137 'start_git_hash': '1', | |
| 138 'end_repository': 'src', | |
| 139 'end_git_hash': '3' | |
| 140 } | |
| 141 response = self.testapp.post('/api/new', params, status=200) | |
| 142 self.assertEqual({'error': 'NotFoundError()'}, | |
| 143 json.loads(response.body)) | |
| 144 | 128 |
| 145 def testPost_InvalidBug(self): | 129 def testPost_InvalidBug(self): |
| 146 params = { | 130 request = dict(_BASE_REQUEST) |
| 147 'configuration': 'chromium-rel-mac11-pro', | 131 request['bug_id'] = 'not_an_int' |
| 148 'test_suite': 'speedometer', | 132 response = self.testapp.post('/api/new', request, status=200) |
| 149 'test': '', | |
| 150 'metric': 'Total', | |
| 151 'auto_explore': '1', | |
| 152 'bug_id': 'not_an_int', | |
| 153 'start_repository': 'src', | |
| 154 'start_git_hash': '1', | |
| 155 'end_repository': 'src', | |
| 156 'end_git_hash': '3' | |
| 157 } | |
| 158 response = self.testapp.post('/api/new', params, status=200) | |
| 159 self.assertEqual({'error': new._ERROR_BUG_ID}, | 133 self.assertEqual({'error': new._ERROR_BUG_ID}, |
| 160 json.loads(response.body)) | 134 json.loads(response.body)) |
| 161 | 135 |
| 162 @mock.patch( | 136 @mock.patch( |
| 163 'dashboard.services.issue_tracker_service.IssueTrackerService', | 137 'dashboard.services.issue_tracker_service.IssueTrackerService', |
| 164 mock.MagicMock()) | 138 mock.MagicMock()) |
| 165 @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) | 139 @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) |
| 166 @mock.patch.object(gitiles_service, 'CommitInfo', mock.MagicMock()) | 140 @mock.patch.object(gitiles_service, 'CommitInfo', mock.MagicMock()) |
| 167 @mock.patch.object(gitiles_service, 'CommitRange') | 141 @mock.patch.object(gitiles_service, 'CommitRange') |
| 168 def testPost_EmptyBug(self, mock_commit_range): | 142 def testPost_EmptyBug(self, mock_commit_range): |
| 169 mock_commit_range.return_value = [ | 143 mock_commit_range.return_value = [ |
| 170 {'commit': '1'}, | 144 {'commit': '1'}, |
| 171 {'commit': '2'}, | 145 {'commit': '2'}, |
| 172 {'commit': '3'}, | 146 {'commit': '3'}, |
| 173 ] | 147 ] |
| 174 params = { | 148 request = dict(_BASE_REQUEST) |
| 175 'configuration': 'chromium-rel-mac11-pro', | 149 request['bug_id'] = '' |
| 176 'test_suite': 'speedometer', | 150 response = self.testapp.post('/api/new', request, status=200) |
| 177 'test': '', | |
| 178 'metric': 'Total', | |
| 179 'auto_explore': '1', | |
| 180 'bug_id': '', | |
| 181 'start_repository': 'src', | |
| 182 'start_git_hash': '1', | |
| 183 'end_repository': 'src', | |
| 184 'end_git_hash': '3' | |
| 185 } | |
| 186 response = self.testapp.post('/api/new', params, status=200) | |
| 187 result = json.loads(response.body) | 151 result = json.loads(response.body) |
| 188 self.assertIn('jobId', result) | 152 self.assertIn('jobId', result) |
| 189 self.assertEqual( | 153 self.assertEqual( |
| 190 result['jobUrl'], | 154 result['jobUrl'], |
| 191 'https://testbed.example.com/job/%s' % result['jobId']) | 155 'https://testbed.example.com/job/%s' % result['jobId']) |
| 192 job = job_module.Job.query().get() | 156 job = job_module.Job.query().get() |
| 193 self.assertEqual(None, job.bug_id) | 157 self.assertEqual(None, job.bug_id) |
| OLD | NEW |