| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """Unit tests for owners.py.""" | 6 """Unit tests for owners.py.""" |
| 7 | 7 |
| 8 import os | 8 import os |
| 9 import sys | 9 import sys |
| 10 import unittest | 10 import unittest |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 peter = 'peter@example.com' | 23 peter = 'peter@example.com' |
| 24 tom = 'tom@example.com' | 24 tom = 'tom@example.com' |
| 25 | 25 |
| 26 | 26 |
| 27 def owners_file(*email_addresses, **kwargs): | 27 def owners_file(*email_addresses, **kwargs): |
| 28 s = '' | 28 s = '' |
| 29 if kwargs.get('comment'): | 29 if kwargs.get('comment'): |
| 30 s += '# %s\n' % kwargs.get('comment') | 30 s += '# %s\n' % kwargs.get('comment') |
| 31 if kwargs.get('noparent'): | 31 if kwargs.get('noparent'): |
| 32 s += 'set noparent\n' | 32 s += 'set noparent\n' |
| 33 if kwargs.get('file'): |
| 34 s += 'file:%s\n' % kwargs.get('file') |
| 33 s += '\n'.join(kwargs.get('lines', [])) + '\n' | 35 s += '\n'.join(kwargs.get('lines', [])) + '\n' |
| 34 return s + '\n'.join(email_addresses) + '\n' | 36 return s + '\n'.join(email_addresses) + '\n' |
| 35 | 37 |
| 36 | 38 |
| 37 def test_repo(): | 39 def test_repo(): |
| 38 return filesystem_mock.MockFileSystem(files={ | 40 return filesystem_mock.MockFileSystem(files={ |
| 39 '/DEPS' : '', | 41 '/DEPS' : '', |
| 40 '/OWNERS': owners_file(owners.EVERYONE), | 42 '/OWNERS': owners_file(owners.EVERYONE), |
| 41 '/base/vlog.h': '', | 43 '/base/vlog.h': '', |
| 42 '/chrome/OWNERS': owners_file(ben, brett), | 44 '/chrome/OWNERS': owners_file(ben, brett), |
| 43 '/chrome/browser/OWNERS': owners_file(brett), | 45 '/chrome/browser/OWNERS': owners_file(brett), |
| 44 '/chrome/browser/defaults.h': '', | 46 '/chrome/browser/defaults.h': '', |
| 45 '/chrome/gpu/OWNERS': owners_file(ken), | 47 '/chrome/gpu/OWNERS': owners_file(ken), |
| 46 '/chrome/gpu/gpu_channel.h': '', | 48 '/chrome/gpu/gpu_channel.h': '', |
| 47 '/chrome/renderer/OWNERS': owners_file(peter), | 49 '/chrome/renderer/OWNERS': owners_file(peter), |
| 48 '/chrome/renderer/gpu/gpu_channel_host.h': '', | 50 '/chrome/renderer/gpu/gpu_channel_host.h': '', |
| 49 '/chrome/renderer/safe_browsing/scorer.h': '', | 51 '/chrome/renderer/safe_browsing/scorer.h': '', |
| 50 '/content/OWNERS': owners_file(john, darin, comment='foo', noparent=True), | 52 '/content/OWNERS': owners_file(john, darin, comment='foo', noparent=True), |
| 51 '/content/content.gyp': '', | 53 '/content/content.gyp': '', |
| 52 '/content/bar/foo.cc': '', | 54 '/content/bar/foo.cc': '', |
| 53 '/content/baz/OWNERS': owners_file(brett), | 55 '/content/baz/OWNERS': owners_file(brett), |
| 54 '/content/baz/froboz.h': '', | 56 '/content/baz/froboz.h': '', |
| 55 '/content/baz/ugly.cc': '', | 57 '/content/baz/ugly.cc': '', |
| 56 '/content/baz/ugly.h': '', | 58 '/content/baz/ugly.h': '', |
| 59 '/content/garply/OWNERS': owners_file(file='test/OWNERS'), |
| 60 '/content/garply/foo.cc': '', |
| 61 '/content/garply/test/OWNERS': owners_file(peter), |
| 62 '/content/qux/OWNERS': owners_file(peter, file='//content/baz/OWNERS'), |
| 63 '/content/qux/foo.cc': '', |
| 57 '/content/views/OWNERS': owners_file(ben, john, owners.EVERYONE, | 64 '/content/views/OWNERS': owners_file(ben, john, owners.EVERYONE, |
| 58 noparent=True), | 65 noparent=True), |
| 59 '/content/views/pie.h': '', | 66 '/content/views/pie.h': '', |
| 60 }) | 67 }) |
| 61 | 68 |
| 62 | 69 |
| 63 class _BaseTestCase(unittest.TestCase): | 70 class _BaseTestCase(unittest.TestCase): |
| 64 def setUp(self): | 71 def setUp(self): |
| 65 self.repo = test_repo() | 72 self.repo = test_repo() |
| 66 self.files = self.repo.files | 73 self.files = self.repo.files |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 202 # This test ensures the mock relpath has the arguments in the right | 209 # This test ensures the mock relpath has the arguments in the right |
| 203 # order; this should probably live someplace else. | 210 # order; this should probably live someplace else. |
| 204 self.assertEquals(self.repo.relpath('foo/bar.c', 'foo/'), 'bar.c') | 211 self.assertEquals(self.repo.relpath('foo/bar.c', 'foo/'), 'bar.c') |
| 205 self.assertEquals(self.repo.relpath('/bar.c', '/'), 'bar.c') | 212 self.assertEquals(self.repo.relpath('/bar.c', '/'), 'bar.c') |
| 206 | 213 |
| 207 def test_per_file_glob_across_dirs_not_allowed(self): | 214 def test_per_file_glob_across_dirs_not_allowed(self): |
| 208 self.files['/OWNERS'] = 'per-file content/*=john@example.org\n' | 215 self.files['/OWNERS'] = 'per-file content/*=john@example.org\n' |
| 209 self.assertRaises(owners.SyntaxErrorInOwnersFile, | 216 self.assertRaises(owners.SyntaxErrorInOwnersFile, |
| 210 self.db().files_not_covered_by, ['DEPS'], [brett]) | 217 self.db().files_not_covered_by, ['DEPS'], [brett]) |
| 211 | 218 |
| 219 def test_file_include_absolute_path(self): |
| 220 self.assert_files_not_covered_by(['content/qux/foo.cc'], [brett], []) |
| 221 self.assert_files_not_covered_by(['content/qux/bar.cc'], [peter], []) |
| 222 self.assert_files_not_covered_by(['content/qux/baz.cc'], |
| 223 [tom], ['content/qux/baz.cc']) |
| 224 |
| 225 def test_file_include_relative_path(self): |
| 226 self.assert_files_not_covered_by(['content/garply/foo.cc'], [peter], []) |
| 227 self.assert_files_not_covered_by(['content/garply/bar.cc'], [darin], []) |
| 228 self.assert_files_not_covered_by(['content/garply/baz.cc'], |
| 229 [tom], ['content/garply/baz.cc']) |
| 230 |
| 231 def test_file_include_per_file_absolute_path(self): |
| 232 self.files['/content/qux/OWNERS'] = owners_file(peter, |
| 233 lines=['per-file foo.*=file://content/baz/OWNERS']) |
| 234 |
| 235 self.assert_files_not_covered_by(['content/qux/foo.cc'], [brett], []) |
| 236 self.assert_files_not_covered_by(['content/qux/baz.cc'], |
| 237 [brett], ['content/qux/baz.cc']) |
| 238 |
| 239 def test_file_include_per_file_relative_path(self): |
| 240 self.files['/content/garply/OWNERS'] = owners_file(brett, |
| 241 lines=['per-file foo.*=file:test/OWNERS']) |
| 242 |
| 243 self.assert_files_not_covered_by(['content/garply/foo.cc'], [peter], []) |
| 244 self.assert_files_not_covered_by(['content/garply/baz.cc'], |
| 245 [peter], ['content/garply/baz.cc']) |
| 246 |
| 247 def test_file_include_recursive(self): |
| 248 self.files['/content/baz/OWNERS'] = owners_file(file='//chrome/gpu/OWNERS') |
| 249 self.assert_files_not_covered_by(['content/qux/foo.cc'], [ken], []) |
| 250 |
| 251 def test_file_include_recursive_loop(self): |
| 252 self.files['/content/baz/OWNERS'] = owners_file(brett, |
| 253 file='//content/qux/OWNERS') |
| 254 self.test_file_include_absolute_path() |
| 255 |
| 256 def test_file_include_different_filename(self): |
| 257 self.files['/owners/garply'] = owners_file(peter) |
| 258 self.files['/content/garply/OWNERS'] = owners_file(john, |
| 259 lines=['per-file foo.*=file://owners/garply']) |
| 260 |
| 261 self.assert_files_not_covered_by(['content/garply/foo.cc'], [peter], []) |
| 262 |
| 212 def assert_syntax_error(self, owners_file_contents): | 263 def assert_syntax_error(self, owners_file_contents): |
| 213 db = self.db() | 264 db = self.db() |
| 214 self.files['/foo/OWNERS'] = owners_file_contents | 265 self.files['/foo/OWNERS'] = owners_file_contents |
| 215 self.files['/foo/DEPS'] = '' | 266 self.files['/foo/DEPS'] = '' |
| 216 try: | 267 try: |
| 217 db.reviewers_for(['foo/DEPS'], None) | 268 db.reviewers_for(['foo/DEPS'], None) |
| 218 self.fail() # pragma: no cover | 269 self.fail() # pragma: no cover |
| 219 except owners.SyntaxErrorInOwnersFile, e: | 270 except owners.SyntaxErrorInOwnersFile, e: |
| 220 self.assertTrue(str(e).startswith('/foo/OWNERS:1')) | 271 self.assertTrue(str(e).startswith('/foo/OWNERS:1')) |
| 221 | 272 |
| 222 def test_syntax_error__unknown_token(self): | 273 def test_syntax_error__unknown_token(self): |
| 223 self.assert_syntax_error('{}\n') | 274 self.assert_syntax_error('{}\n') |
| 224 | 275 |
| 225 def test_syntax_error__unknown_set(self): | 276 def test_syntax_error__unknown_set(self): |
| 226 self.assert_syntax_error('set myfatherisbillgates\n') | 277 self.assert_syntax_error('set myfatherisbillgates\n') |
| 227 | 278 |
| 228 def test_syntax_error__bad_email(self): | 279 def test_syntax_error__bad_email(self): |
| 229 self.assert_syntax_error('ben\n') | 280 self.assert_syntax_error('ben\n') |
| 230 | 281 |
| 282 def test_syntax_error__invalid_absolute_file(self): |
| 283 self.assert_syntax_error('file://foo/bar/baz\n') |
| 284 |
| 285 def test_syntax_error__invalid_relative_file(self): |
| 286 self.assert_syntax_error('file:foo/bar/baz\n') |
| 287 |
| 231 | 288 |
| 232 class ReviewersForTest(_BaseTestCase): | 289 class ReviewersForTest(_BaseTestCase): |
| 233 def assert_reviewers_for(self, files, potential_suggested_reviewers, | 290 def assert_reviewers_for(self, files, potential_suggested_reviewers, |
| 234 author=None): | 291 author=None): |
| 235 db = self.db() | 292 db = self.db() |
| 236 suggested_reviewers = db.reviewers_for(set(files), author) | 293 suggested_reviewers = db.reviewers_for(set(files), author) |
| 237 self.assertTrue(suggested_reviewers in | 294 self.assertTrue(suggested_reviewers in |
| 238 [set(suggestion) for suggestion in potential_suggested_reviewers]) | 295 [set(suggestion) for suggestion in potential_suggested_reviewers]) |
| 239 | 296 |
| 240 def test_reviewers_for__basic_functionality(self): | 297 def test_reviewers_for__basic_functionality(self): |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 315 self.assert_reviewers_for(['chrome/OWNERS', | 372 self.assert_reviewers_for(['chrome/OWNERS', |
| 316 'chrome/renderer/gpu/gpu_channel_host.h'], | 373 'chrome/renderer/gpu/gpu_channel_host.h'], |
| 317 [[ben, ken], | 374 [[ben, ken], |
| 318 [brett, ken]]) | 375 [brett, ken]]) |
| 319 | 376 |
| 320 def test_reviewers_for__author_is_known(self): | 377 def test_reviewers_for__author_is_known(self): |
| 321 # We should never suggest ken as a reviewer for his own changes. | 378 # We should never suggest ken as a reviewer for his own changes. |
| 322 self.assert_reviewers_for(['chrome/gpu/gpu_channel.h'], | 379 self.assert_reviewers_for(['chrome/gpu/gpu_channel.h'], |
| 323 [[ben], [brett]], author=ken) | 380 [[ben], [brett]], author=ken) |
| 324 | 381 |
| 382 def test_reviewers_file_includes__absolute(self): |
| 383 self.assert_reviewers_for(['content/qux/foo.cc'], |
| 384 [[peter], [brett], [john], [darin]]) |
| 385 |
| 386 def test_reviewers_file_includes__relative(self): |
| 387 self.assert_reviewers_for(['content/garply/foo.cc'], |
| 388 [[peter], [john], [darin]]) |
| 389 |
| 390 def test_reviewers_file_includes__per_file(self): |
| 391 self.files['/content/garply/OWNERS'] = owners_file(brett, |
| 392 lines=['per-file foo.*=file:test/OWNERS']) |
| 393 |
| 394 self.assert_reviewers_for(['content/garply/foo.cc'], |
| 395 [[brett], [peter]]) |
| 396 self.assert_reviewers_for(['content/garply/bar.cc'], |
| 397 [[brett]]) |
| 398 |
| 399 def test_reviewers_file_includes__per_file_noparent(self): |
| 400 self.files['/content/garply/OWNERS'] = owners_file(brett, |
| 401 lines=['per-file foo.*=set noparent', |
| 402 'per-file foo.*=file:test/OWNERS']) |
| 403 |
| 404 self.assert_reviewers_for(['content/garply/foo.cc'], |
| 405 [[peter]]) |
| 406 self.assert_reviewers_for(['content/garply/bar.cc'], |
| 407 [[brett]]) |
| 408 |
| 325 | 409 |
| 326 class LowestCostOwnersTest(_BaseTestCase): | 410 class LowestCostOwnersTest(_BaseTestCase): |
| 327 # Keep the data in the test_lowest_cost_owner* methods as consistent with | 411 # Keep the data in the test_lowest_cost_owner* methods as consistent with |
| 328 # test_repo() where possible to minimize confusion. | 412 # test_repo() where possible to minimize confusion. |
| 329 | 413 |
| 330 def check(self, possible_owners, dirs, *possible_lowest_cost_owners): | 414 def check(self, possible_owners, dirs, *possible_lowest_cost_owners): |
| 331 suggested_owner = owners.Database.lowest_cost_owner(possible_owners, dirs) | 415 suggested_owner = owners.Database.lowest_cost_owner(possible_owners, dirs) |
| 332 self.assertTrue(suggested_owner in possible_lowest_cost_owners) | 416 self.assertTrue(suggested_owner in possible_lowest_cost_owners) |
| 333 | 417 |
| 334 def test_one_dir_with_owner(self): | 418 def test_one_dir_with_owner(self): |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 392 ('chrome/browser', 2)], | 476 ('chrome/browser', 2)], |
| 393 ken: [('chrome/gpu', 1)], | 477 ken: [('chrome/gpu', 1)], |
| 394 peter: [('chrome/renderer', 1)], | 478 peter: [('chrome/renderer', 1)], |
| 395 brett: [('chrome/browser', 1)]}, | 479 brett: [('chrome/browser', 1)]}, |
| 396 ['chrome/gpu', 'chrome/renderer', | 480 ['chrome/gpu', 'chrome/renderer', |
| 397 'chrome/browser'], | 481 'chrome/browser'], |
| 398 ben) | 482 ben) |
| 399 | 483 |
| 400 if __name__ == '__main__': | 484 if __name__ == '__main__': |
| 401 unittest.main() | 485 unittest.main() |
| OLD | NEW |