123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350 |
- #!/usr/bin/env vpython3
- # Copyright (c) 2018 The Chromium Authors. All rights reserved.
- # Use of this source code is governed by a BSD-style license that can be
- # found in the LICENSE file.
- import logging
- import os
- import sys
- import subprocess
- import unittest
- from unittest import mock
- ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
- sys.path.insert(0, ROOT_DIR)
- import roll_dep
- from testing_support import fake_repos
- ROLL_DEP = os.path.join(ROOT_DIR, 'roll-dep')
- GCLIENT = os.path.join(ROOT_DIR, 'gclient')
- # TODO: Should fix these warnings.
- # pylint: disable=line-too-long
- def create_deps_content(git_base, path_to_revision_map):
- """
- Create a DEPS file content string with the given dependency mappings.
- Args:
- git_base: The base URL for git repositories
- path_to_revision_map: Dictionary mapping dependency paths to their revisions
- Returns:
- String with the complete DEPS file content including standard hooks
- """
- dep_lines = []
- git_base = git_base.replace('\\', '\\\\')
- for path, revision in path_to_revision_map.items():
- dep_lines.append(f' "{path}": "file://{git_base}repo_2@{revision}",')
- # Combine all parts with standard hooks.
- deps_content = [
- 'deps = {',
- '\n'.join(dep_lines),
- '}',
- 'hooks = [',
- ' {"action": ["foo", "--android", "{checkout_android}"]}',
- ']',
- ]
- return '\n'.join(deps_content)
- class FakeRepos(fake_repos.FakeReposBase):
- NB_GIT_REPOS = 2
- def populateGit(self):
- for x in range(1,4):
- self._commit_git('repo_2', {'origin': f'git/repo_2@{x}'})
- # repo_2@1 is the default revision.
- # Anything under 'third_party/not_supported' tests handling unsupported
- # cases.
- repo2_revision = self.git_hashes['repo_2'][1][0]
- self._commit_git(
- 'repo_1', {
- 'DEPS': create_deps_content(self.git_base, {
- 'src/foo': repo2_revision,
- 'src/third_party/repo_2/src': repo2_revision,
- 'src/third_party/repo_2B/src': repo2_revision,
- 'src/third_party/not_supported/with_divider/src': repo2_revision,
- 'src/third_party/not_supported/multiple_revisions/src': repo2_revision,
- 'src/third_party/not_supported/no_revision/src': repo2_revision
- }),
- 'README.chromium': '\n'.join([
- 'Name: test repo',
- 'URL: https://example.com',
- 'Version: 1.0',
- 'Revision: abcabc123123',
- 'License: MIT',
- ]),
- 'third_party/repo_2/README.chromium': '\n'.join([
- 'Name: test repo 2',
- 'URL: https://example.com',
- 'Version: 1.0',
- 'Revision: abc1234',
- 'License: MIT',
- ]),
- 'third_party/repo_2B/README.chromium': '\n'.join([
- 'Name: Override DEPS value for revision',
- 'URL: https://example.com',
- 'Version: 1.0',
- 'Revision: DEPS',
- 'License: MIT',
- ]),
- 'third_party/not_supported/with_divider/README.chromium': '\n'.join([
- 'Name: Deps divider not supported',
- 'URL: https://example.com',
- 'Version: 1.0',
- 'Revision: abc1234',
- 'License: MIT',
- '-------------------- DEPENDENCY DIVIDER --------------------',
- 'Name: So nothing here should change',
- 'URL: https://example.com',
- 'Version: 1.0',
- 'Revision: abc1234',
- 'License: MIT',
- ]),
- 'third_party/not_supported/multiple_revisions/README.chromium': '\n'.join([
- 'Name: Multiple revisions',
- 'URL: https://example.com',
- 'Version: 1.0',
- 'Revision: abc1234',
- 'License: MIT',
- 'Revision: abc1235', # This should not happen.
- ]),
- 'third_party/not_supported/no_revision/README.chromium': '\n'.join([
- 'Name: No revision',
- 'URL: https://example.com',
- 'Version: 1.0',
- 'License: MIT',
- ]),
- })
- class RollDepTest(fake_repos.FakeReposTestBase):
- FAKE_REPOS_CLASS = FakeRepos
- def setUp(self):
- super(RollDepTest, self).setUp()
- # Make sure it doesn't try to auto update when testing!
- self.env = os.environ.copy()
- self.env['DEPOT_TOOLS_UPDATE'] = '0'
- self.env['DEPOT_TOOLS_METRICS'] = '0'
- # Suppress Python 3 warnings and other test undesirables.
- self.env['GCLIENT_TEST'] = '1'
- self.maxDiff = None
- self.enabled = self.FAKE_REPOS.set_up_git()
- self.src_dir = os.path.join(self.root_dir, 'src')
- self.foo_dir = os.path.join(self.src_dir, 'foo')
- self.all_repos = [
- 'src/foo',
- 'src/third_party/repo_2/src',
- 'src/third_party/repo_2B/src',
- 'src/third_party/not_supported/with_divider/src',
- 'src/third_party/not_supported/multiple_revisions/src',
- 'src/third_party/not_supported/no_revision/src',
- ]
- if self.enabled:
- self.call([
- GCLIENT, 'config', 'file://' + self.git_base + 'repo_1',
- '--name', 'src'
- ],
- cwd=self.root_dir)
- self.call([GCLIENT, 'sync'], cwd=self.root_dir)
- def call(self, cmd, cwd=None):
- cwd = cwd or self.src_dir
- process = subprocess.Popen(cmd,
- cwd=cwd,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- env=self.env,
- shell=sys.platform.startswith('win'))
- stdout, stderr = process.communicate()
- logging.debug("XXX: %s\n%s\nXXX" % (' '.join(cmd), stdout))
- logging.debug("YYY: %s\n%s\nYYY" % (' '.join(cmd), stderr))
- stdout = stdout.decode('utf-8')
- stderr = stderr.decode('utf-8')
- return (stdout.replace('\r\n',
- '\n'), stderr.replace('\r\n',
- '\n'), process.returncode)
- def assert_deps_match(self, expected_path_to_revision_map):
- # Assume everything is at the default revision and only update the
- # provided paths.
- default_revision = self.githash('repo_2', 1)
- expected_map = {path: default_revision for path in self.all_repos}
- expected_map.update(expected_path_to_revision_map)
- for path, revision in expected_map.items():
- with self.subTest(path=path):
- path_dir = os.path.join(self.root_dir, path)
- self.assertEqual(self.gitrevparse(path_dir), revision)
- with open(os.path.join(self.src_dir, 'DEPS')) as f:
- actual_content = f.read()
- with self.subTest(path='DEPS'):
- expected_content = create_deps_content(self.git_base,expected_map)
- self.assertEqual(expected_content, actual_content)
- def testRollsDep(self):
- if not self.enabled:
- return
- stdout, stderr, returncode = self.call([ROLL_DEP]+self.all_repos)
- latest_revision = self.githash('repo_2', 3)
- self.assertEqual(stderr, '')
- self.assertEqual(returncode, 0)
- # All deps should be rolled to the latest revision.
- self.assert_deps_match({p: latest_revision for p in self.all_repos})
- commit_message = self.call(['git', 'log', '-n', '1'])[0]
- expected_message = 'Roll src/foo/ %s..%s (2 commits)' % (self.githash(
- 'repo_2', 1)[:9], latest_revision[:9])
- self.assertIn(expected_message, stdout)
- self.assertIn(expected_message, commit_message)
- def testRollsDepWithReadme(self):
- """Tests roll-dep when updating README.chromium files."""
- if not self.enabled:
- return
- stdout, stderr, returncode = self.call(
- [ROLL_DEP]+self.all_repos
- )
- latest_revision = self.githash('repo_2', 3)
- # All deps should be rolled to the latest revision (3).
- self.assert_deps_match({p: latest_revision for p in self.all_repos})
- self.assertEqual(stderr, '')
- self.assertEqual(returncode, 0)
- for path in self.all_repos:
- with self.subTest(path=path):
- contents = ''
- readme_path = os.path.join(self.root_dir, path, os.path.pardir, 'README.chromium')
- if os.path.exists(readme_path):
- with open(readme_path, 'r') as f:
- contents = f.read()
- if path == 'src/third_party/not_supported/no_revision/src':
- self.assertIn('README.chromium contains 0 Revision: lines', stdout)
- if 'not_supported' in path:
- self.assertNotIn(latest_revision, contents)
- continue
- # Check that the revision was updated.
- self.assertIn(f'Revision: {latest_revision}', contents)
- self.assertNotIn('Revision: abcabc123123', contents)
- self.assertNotIn('No README.chromium found', stdout)
- def testRollsDepReviewers(self):
- if not self.enabled:
- return
- stdout, stderr, returncode = self.call([
- ROLL_DEP, 'src/foo', '-r', 'foo@example.com', '-r',
- 'bar@example.com,baz@example.com'
- ])
- self.assertEqual(stderr, '')
- self.assertEqual(returncode, 0)
- expected_message = 'R=foo@example.com,bar@example.com,baz@example.com'
- self.assertIn(expected_message, stdout)
- def testRollsDepToSpecificRevision(self):
- if not self.enabled:
- return
- specified_revision = self.githash('repo_2', 2)
- stdout, stderr, returncode = self.call(
- [ROLL_DEP, 'src/foo', '--roll-to', specified_revision])
- self.assertEqual(stderr, '')
- self.assertEqual(returncode, 0)
- self.assert_deps_match({
- 'src/foo': specified_revision,
- })
- commit_message = self.call(['git', 'log', '-n', '1'])[0]
- expected_message = 'Roll src/foo/ %s..%s (1 commit)' % (self.githash(
- 'repo_2', 1)[:9], self.githash('repo_2', 2)[:9])
- self.assertIn(expected_message, stdout)
- self.assertIn(expected_message, commit_message)
- def testRollsDepLogLimit(self):
- if not self.enabled:
- return
- stdout, stderr, returncode = self.call(
- [ROLL_DEP, 'src/foo', '--log-limit', '1'])
- latest_revision = self.githash('repo_2', 3)
- self.assertEqual(stderr, '')
- self.assertEqual(returncode, 0)
- self.assert_deps_match({
- 'src/foo':latest_revision,
- })
- commit_message = self.call(['git', 'log', '-n', '1'])[0]
- expected_message = 'Roll src/foo/ %s..%s (2 commits)' % (self.githash(
- 'repo_2', 1)[:9], self.githash('repo_2', 3)[:9])
- self.assertIn(expected_message, stdout)
- self.assertIn(expected_message, commit_message)
- class CommitMessageTest(unittest.TestCase):
- def setUp(self):
- self.logs = '\n'.join([
- '2024-04-05 alice Goodbye',
- '2024-04-03 bob Hello World',
- ])
- # Mock the `git log` call.
- mock.patch('roll_dep.check_output', return_value=self.logs).start()
- self.addCleanup(mock.patch.stopall)
- def testShowShortLog(self):
- message = roll_dep.generate_commit_message(
- '/path/to/dir', 'dep', 'abc', 'def',
- 'https://chromium.googlesource.com', True, 10)
- self.assertIn('Roll dep/ abc..def (2 commits)', message)
- self.assertIn('$ git log', message)
- self.assertIn(self.logs, message)
- def testHideShortLog(self):
- message = roll_dep.generate_commit_message(
- '/path/to/dir', 'dep', 'abc', 'def',
- 'https://chromium.googlesource.com', False, 10)
- self.assertNotIn('$ git log', message)
- self.assertNotIn(self.logs, message)
- def testShouldShowLogWithPublicHost(self):
- self.assertTrue(
- roll_dep.should_show_log(
- 'https://chromium.googlesource.com/project'))
- def testShouldNotShowLogWithPrivateHost(self):
- self.assertFalse(
- roll_dep.should_show_log(
- 'https://private.googlesource.com/project'))
- if __name__ == '__main__':
- level = logging.DEBUG if '-v' in sys.argv else logging.FATAL
- logging.basicConfig(level=level,
- format='%(asctime).19s %(levelname)s %(filename)s:'
- '%(lineno)s %(message)s')
- unittest.main()
|