| #!/usr/bin/env python |
| # Copyright (c) 2012 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. |
| |
| """Smoke tests for gclient.py. |
| |
| Shell out 'gclient' and run basic conformance tests. |
| |
| This test assumes GClientSmokeBase.URL_BASE is valid. |
| """ |
| |
| import json |
| import logging |
| import os |
| import re |
| import subprocess |
| import sys |
| import unittest |
| |
| ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
| sys.path.insert(0, ROOT_DIR) |
| |
| import gclient_utils |
| import scm as gclient_scm |
| import subprocess2 |
| from testing_support import fake_repos |
| from testing_support.fake_repos import join, write |
| |
| GCLIENT_PATH = os.path.join(ROOT_DIR, 'gclient') |
| COVERAGE = False |
| |
| |
| class GClientSmokeBase(fake_repos.FakeReposTestBase): |
| def setUp(self): |
| super(GClientSmokeBase, 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' |
| |
| def gclient(self, cmd, cwd=None): |
| if not cwd: |
| cwd = self.root_dir |
| if COVERAGE: |
| # Don't use the wrapper script. |
| cmd_base = ['coverage', 'run', '-a', GCLIENT_PATH + '.py'] |
| else: |
| cmd_base = [GCLIENT_PATH] |
| cmd = cmd_base + cmd |
| process = subprocess.Popen(cmd, cwd=cwd, env=self.env, |
| stdout=subprocess.PIPE, stderr=subprocess.PIPE, |
| shell=sys.platform.startswith('win'), |
| universal_newlines=True) |
| (stdout, stderr) = process.communicate() |
| logging.debug("XXX: %s\n%s\nXXX" % (' '.join(cmd), stdout)) |
| logging.debug("YYY: %s\n%s\nYYY" % (' '.join(cmd), stderr)) |
| return (stdout.replace('\r\n', '\n'), stderr.replace('\r\n', '\n'), |
| process.returncode) |
| |
| def untangle(self, stdout): |
| """Separates output based on thread IDs.""" |
| tasks = {} |
| remaining = [] |
| task_id = 0 |
| for line in stdout.splitlines(False): |
| m = re.match(r'^(\d)+>(.*)$', line) |
| if not m: |
| if task_id: |
| # Lines broken with carriage breaks don't have a thread ID, but belong |
| # to the last seen thread ID. |
| tasks.setdefault(task_id, []).append(line) |
| else: |
| remaining.append(line) |
| else: |
| self.assertEqual([], remaining) |
| task_id = int(m.group(1)) |
| tasks.setdefault(task_id, []).append(m.group(2)) |
| out = [] |
| for key in sorted(tasks.keys()): |
| out.extend(tasks[key]) |
| out.extend(remaining) |
| return '\n'.join(out) |
| |
| def parseGclient(self, cmd, items, expected_stderr='', untangle=False): |
| """Parse gclient's output to make it easier to test. |
| If untangle is True, tries to sort out the output from parallel checkout.""" |
| (stdout, stderr, returncode) = self.gclient(cmd) |
| if untangle: |
| stdout = self.untangle(stdout) |
| self.checkString(expected_stderr, stderr) |
| self.assertEqual(0, returncode) |
| return self.checkBlock(stdout, items) |
| |
| def splitBlock(self, stdout): |
| """Split gclient's output into logical execution blocks. |
| ___ running 'foo' at '/bar' |
| (...) |
| ___ running 'baz' at '/bar' |
| (...) |
| |
| will result in 2 items of len((...).splitlines()) each. |
| """ |
| results = [] |
| for line in stdout.splitlines(False): |
| # Intentionally skips empty lines. |
| if not line: |
| continue |
| if not line.startswith('__'): |
| if results: |
| results[-1].append(line) |
| else: |
| # TODO(maruel): gclient's git stdout is inconsistent. |
| # This should fail the test instead!! |
| pass |
| continue |
| |
| match = re.match(r'^________ ([a-z]+) \'(.*)\' in \'(.*)\'$', line) |
| if match: |
| results.append([[match.group(1), match.group(2), match.group(3)]]) |
| continue |
| |
| match = re.match(r'^_____ (.*) is missing, synching instead$', line) |
| if match: |
| # Blah, it's when a dependency is deleted, we should probably not |
| # output this message. |
| results.append([line]) |
| continue |
| |
| # These two regexps are a bit too broad, they are necessary only for git |
| # checkouts. |
| if (re.match(r'_____ [^ ]+ at [^ ]+', line) or |
| re.match(r'_____ [^ ]+ : Attempting rebase onto [0-9a-f]+...', line)): |
| continue |
| |
| # Fail for any unrecognized lines that start with '__'. |
| self.fail(line) |
| return results |
| |
| def checkBlock(self, stdout, items): |
| results = self.splitBlock(stdout) |
| for i in range(min(len(results), len(items))): |
| if isinstance(items[i], (list, tuple)): |
| verb = items[i][0] |
| path = items[i][1] |
| else: |
| verb = items[i] |
| path = self.root_dir |
| self.checkString(results[i][0][0], verb, (i, results[i][0][0], verb)) |
| if sys.platform == 'win32': |
| # Make path lower case since casing can change randomly. |
| self.checkString( |
| results[i][0][2].lower(), |
| path.lower(), |
| (i, results[i][0][2].lower(), path.lower())) |
| else: |
| self.checkString(results[i][0][2], path, (i, results[i][0][2], path)) |
| self.assertEqual(len(results), len(items), (stdout, items, len(results))) |
| return results |
| |
| |
| class GClientSmoke(GClientSmokeBase): |
| """Doesn't require git-daemon.""" |
| @property |
| def git_base(self): |
| return 'git://random.server/git/' |
| |
| def testNotConfigured(self): |
| res = ('', 'Error: client not configured; see \'gclient config\'\n', 1) |
| self.check(res, self.gclient(['diff'])) |
| self.check(res, self.gclient(['pack'])) |
| self.check(res, self.gclient(['revert'])) |
| self.check(res, self.gclient(['revinfo'])) |
| self.check(res, self.gclient(['runhooks'])) |
| self.check(res, self.gclient(['status'])) |
| self.check(res, self.gclient(['sync'])) |
| self.check(res, self.gclient(['update'])) |
| |
| def testConfig(self): |
| # Get any bootstrapping out of the way. |
| results = self.gclient(['version']) |
| self.assertEqual(results[2], 0) |
| |
| p = join(self.root_dir, '.gclient') |
| def test(cmd, expected): |
| if os.path.exists(p): |
| os.remove(p) |
| results = self.gclient(cmd) |
| self.check(('', '', 0), results) |
| mode = 'r' if sys.version_info.major == 3 else 'rU' |
| with open(p, mode) as f: |
| self.checkString(expected, f.read()) |
| |
| test(['config', self.git_base + 'src/'], |
| ('solutions = [\n' |
| ' { "name" : "src",\n' |
| ' "url" : "%ssrc",\n' |
| ' "deps_file" : "DEPS",\n' |
| ' "managed" : True,\n' |
| ' "custom_deps" : {\n' |
| ' },\n' |
| ' "custom_vars": {},\n' |
| ' },\n' |
| ']\n' % self.git_base)) |
| |
| test(['config', self.git_base + 'repo_1', '--name', 'src', |
| '--cache-dir', 'none'], |
| ('solutions = [\n' |
| ' { "name" : "src",\n' |
| ' "url" : "%srepo_1",\n' |
| ' "deps_file" : "DEPS",\n' |
| ' "managed" : True,\n' |
| ' "custom_deps" : {\n' |
| ' },\n' |
| ' "custom_vars": {},\n' |
| ' },\n' |
| ']\n' |
| 'cache_dir = None\n') % self.git_base) |
| |
| test(['config', 'https://example.com/foo', 'faa', |
| '--cache-dir', 'something'], |
| 'solutions = [\n' |
| ' { "name" : "foo",\n' |
| ' "url" : "https://example.com/foo",\n' |
| ' "deps_file" : "DEPS",\n' |
| ' "managed" : True,\n' |
| ' "custom_deps" : {\n' |
| ' },\n' |
| ' "custom_vars": {},\n' |
| ' },\n' |
| ']\n' |
| 'cache_dir = \'something\'\n') |
| |
| test(['config', 'https://example.com/foo', '--deps', 'blah'], |
| 'solutions = [\n' |
| ' { "name" : "foo",\n' |
| ' "url" : "https://example.com/foo",\n' |
| ' "deps_file" : "blah",\n' |
| ' "managed" : True,\n' |
| ' "custom_deps" : {\n' |
| ' },\n' |
| ' "custom_vars": {},\n' |
| ' },\n' |
| ']\n') |
| |
| test(['config', self.git_base + 'src/', |
| '--custom-var', 'bool_var=True', |
| '--custom-var', 'str_var="abc"'], |
| ('solutions = [\n' |
| ' { "name" : "src",\n' |
| ' "url" : "%ssrc",\n' |
| ' "deps_file" : "DEPS",\n' |
| ' "managed" : True,\n' |
| ' "custom_deps" : {\n' |
| ' },\n' |
| ' "custom_vars": {\'bool_var\': True, \'str_var\': \'abc\'},\n' |
| ' },\n' |
| ']\n') % self.git_base) |
| |
| test(['config', '--spec', '["blah blah"]'], '["blah blah"]') |
| |
| os.remove(p) |
| results = self.gclient(['config', 'foo', 'faa', 'fuu']) |
| err = ('Usage: gclient.py config [options] [url]\n\n' |
| 'gclient.py: error: Inconsistent arguments. Use either --spec or one' |
| ' or 2 args\n') |
| self.check(('', err, 2), results) |
| self.assertFalse(os.path.exists(join(self.root_dir, '.gclient'))) |
| |
| def testSolutionNone(self): |
| results = self.gclient(['config', '--spec', |
| 'solutions=[{"name": "./", "url": None}]']) |
| self.check(('', '', 0), results) |
| results = self.gclient(['sync']) |
| self.check(('', '', 0), results) |
| self.assertTree({}) |
| results = self.gclient(['revinfo']) |
| self.check(('./: None\n', '', 0), results) |
| self.check(('', '', 0), self.gclient(['diff'])) |
| self.assertTree({}) |
| self.check(('', '', 0), self.gclient(['pack'])) |
| self.check(('', '', 0), self.gclient(['revert'])) |
| self.assertTree({}) |
| self.check(('', '', 0), self.gclient(['runhooks'])) |
| self.assertTree({}) |
| self.check(('', '', 0), self.gclient(['status'])) |
| |
| def testDifferentTopLevelDirectory(self): |
| # Check that even if the .gclient file does not mention the directory src |
| # itself, but it is included via dependencies, the .gclient file is used. |
| self.gclient(['config', self.git_base + 'src.DEPS']) |
| deps = join(self.root_dir, 'src.DEPS') |
| os.mkdir(deps) |
| subprocess2.check_output(['git', 'init'], cwd=deps) |
| write(join(deps, 'DEPS'), |
| 'deps = { "src": "%ssrc" }' % (self.git_base)) |
| subprocess2.check_output(['git', 'add', 'DEPS'], cwd=deps) |
| subprocess2.check_output( |
| ['git', 'commit', '-a', '-m', 'DEPS file'], cwd=deps) |
| src = join(self.root_dir, 'src') |
| os.mkdir(src) |
| subprocess2.check_output(['git', 'init'], cwd=src) |
| res = self.gclient(['status', '--jobs', '1', '-v'], src) |
| self.checkBlock(res[0], [('running', deps), ('running', src)]) |
| |
| |
| class GClientSmokeGIT(GClientSmokeBase): |
| def setUp(self): |
| super(GClientSmokeGIT, self).setUp() |
| self.enabled = self.FAKE_REPOS.set_up_git() |
| |
| def testSync(self): |
| if not self.enabled: |
| return |
| self.gclient(['config', self.git_base + 'repo_1', '--name', 'src']) |
| # Test unversioned checkout. |
| self.parseGclient( |
| ['sync', '--deps', 'mac', '--jobs', '1'], |
| ['running', 'running', 'running']) |
| # TODO(maruel): http://crosbug.com/3582 hooks run even if not matching, must |
| # add sync parsing to get the list of updated files. |
| tree = self.mangle_git_tree(('repo_1@2', 'src'), |
| ('repo_2@1', 'src/repo2'), |
| ('repo_3@2', 'src/repo2/repo_renamed')) |
| tree['src/git_hooked1'] = 'git_hooked1' |
| tree['src/git_hooked2'] = 'git_hooked2' |
| self.assertTree(tree) |
| |
| # Manually remove git_hooked1 before synching to make sure it's not |
| # recreated. |
| os.remove(join(self.root_dir, 'src', 'git_hooked1')) |
| |
| # Test incremental versioned sync: sync backward. |
| self.parseGclient( |
| ['sync', '--jobs', '1', '--revision', |
| 'src@' + self.githash('repo_1', 1), |
| '--deps', 'mac', '--delete_unversioned_trees'], |
| ['deleting']) |
| tree = self.mangle_git_tree(('repo_1@1', 'src'), |
| ('repo_2@2', 'src/repo2'), |
| ('repo_3@1', 'src/repo2/repo3'), |
| ('repo_4@2', 'src/repo4')) |
| tree['src/git_hooked2'] = 'git_hooked2' |
| tree['src/repo2/gclient.args'] = '\n'.join([ |
| '# Generated from \'DEPS\'', |
| 'false_var = false', |
| 'false_str_var = false', |
| 'true_var = true', |
| 'true_str_var = true', |
| 'str_var = "abc"', |
| 'cond_var = false', |
| ]) |
| self.assertTree(tree) |
| # Test incremental sync: delete-unversioned_trees isn't there. |
| self.parseGclient( |
| ['sync', '--deps', 'mac', '--jobs', '1'], |
| ['running', 'running']) |
| tree = self.mangle_git_tree(('repo_1@2', 'src'), |
| ('repo_2@1', 'src/repo2'), |
| ('repo_3@1', 'src/repo2/repo3'), |
| ('repo_3@2', 'src/repo2/repo_renamed'), |
| ('repo_4@2', 'src/repo4')) |
| tree['src/git_hooked1'] = 'git_hooked1' |
| tree['src/git_hooked2'] = 'git_hooked2' |
| tree['src/repo2/gclient.args'] = '\n'.join([ |
| '# Generated from \'DEPS\'', |
| 'false_var = false', |
| 'false_str_var = false', |
| 'true_var = true', |
| 'true_str_var = true', |
| 'str_var = "abc"', |
| 'cond_var = false', |
| ]) |
| self.assertTree(tree) |
| |
| def testSyncJsonOutput(self): |
| self.gclient(['config', self.git_base + 'repo_1', '--name', 'src']) |
| output_json = os.path.join(self.root_dir, 'output.json') |
| self.gclient(['sync', '--deps', 'mac', '--output-json', output_json]) |
| with open(output_json) as f: |
| output_json = json.load(f) |
| |
| self.maxDiff = None |
| out = { |
| 'solutions': { |
| 'src/': { |
| 'scm': 'git', |
| 'url': self.git_base + 'repo_1', |
| 'revision': self.githash('repo_1', 2), |
| 'was_processed': True, |
| }, |
| 'src/repo2/': { |
| 'scm': 'git', |
| 'url': |
| self.git_base + 'repo_2@' + self.githash('repo_2', 1)[:7], |
| 'revision': self.githash('repo_2', 1), |
| 'was_processed': True, |
| }, |
| 'src/repo2/repo_renamed/': { |
| 'scm': 'git', |
| 'url': self.git_base + 'repo_3', |
| 'revision': self.githash('repo_3', 2), |
| 'was_processed': True, |
| }, |
| 'src/should_not_process/': { |
| 'scm': None, |
| 'url': self.git_base + 'repo_4', |
| 'revision': None, |
| 'was_processed': False, |
| }, |
| }, |
| } |
| self.assertEqual(out, output_json) |
| |
| def testSyncIgnoredSolutionName(self): |
| """TODO(maruel): This will become an error soon.""" |
| if not self.enabled: |
| return |
| self.gclient(['config', self.git_base + 'repo_1', '--name', 'src']) |
| self.parseGclient( |
| ['sync', '--deps', 'mac', '--jobs', '1', |
| '--revision', 'invalid@' + self.githash('repo_1', 1)], |
| ['running', 'running', 'running'], |
| 'Please fix your script, having invalid --revision flags ' |
| 'will soon be considered an error.\n') |
| tree = self.mangle_git_tree(('repo_1@2', 'src'), |
| ('repo_2@1', 'src/repo2'), |
| ('repo_3@2', 'src/repo2/repo_renamed')) |
| tree['src/git_hooked1'] = 'git_hooked1' |
| tree['src/git_hooked2'] = 'git_hooked2' |
| self.assertTree(tree) |
| |
| def testSyncNoSolutionName(self): |
| if not self.enabled: |
| return |
| # When no solution name is provided, gclient uses the first solution listed. |
| self.gclient(['config', self.git_base + 'repo_1', '--name', 'src']) |
| self.parseGclient( |
| ['sync', '--deps', 'mac', '--jobs', '1', |
| '--revision', self.githash('repo_1', 1)], |
| ['running']) |
| tree = self.mangle_git_tree(('repo_1@1', 'src'), |
| ('repo_2@2', 'src/repo2'), |
| ('repo_3@1', 'src/repo2/repo3'), |
| ('repo_4@2', 'src/repo4')) |
| tree['src/repo2/gclient.args'] = '\n'.join([ |
| '# Generated from \'DEPS\'', |
| 'false_var = false', |
| 'false_str_var = false', |
| 'true_var = true', |
| 'true_str_var = true', |
| 'str_var = "abc"', |
| 'cond_var = false', |
| ]) |
| self.assertTree(tree) |
| |
| def testSyncJobs(self): |
| if not self.enabled: |
| return |
| self.gclient(['config', self.git_base + 'repo_1', '--name', 'src']) |
| # Test unversioned checkout. |
| self.parseGclient( |
| ['sync', '--deps', 'mac', '--jobs', '8'], |
| ['running', 'running', 'running'], |
| untangle=True) |
| # TODO(maruel): http://crosbug.com/3582 hooks run even if not matching, must |
| # add sync parsing to get the list of updated files. |
| tree = self.mangle_git_tree(('repo_1@2', 'src'), |
| ('repo_2@1', 'src/repo2'), |
| ('repo_3@2', 'src/repo2/repo_renamed')) |
| tree['src/git_hooked1'] = 'git_hooked1' |
| tree['src/git_hooked2'] = 'git_hooked2' |
| self.assertTree(tree) |
| |
| # Manually remove git_hooked1 before synching to make sure it's not |
| # recreated. |
| os.remove(join(self.root_dir, 'src', 'git_hooked1')) |
| |
| # Test incremental versioned sync: sync backward. |
| # Use --jobs 1 otherwise the order is not deterministic. |
| self.parseGclient( |
| ['sync', '--revision', 'src@' + self.githash('repo_1', 1), |
| '--deps', 'mac', '--delete_unversioned_trees', '--jobs', '1'], |
| ['deleting'], |
| untangle=True) |
| tree = self.mangle_git_tree(('repo_1@1', 'src'), |
| ('repo_2@2', 'src/repo2'), |
| ('repo_3@1', 'src/repo2/repo3'), |
| ('repo_4@2', 'src/repo4')) |
| tree['src/git_hooked2'] = 'git_hooked2' |
| tree['src/repo2/gclient.args'] = '\n'.join([ |
| '# Generated from \'DEPS\'', |
| 'false_var = false', |
| 'false_str_var = false', |
| 'true_var = true', |
| 'true_str_var = true', |
| 'str_var = "abc"', |
| 'cond_var = false', |
| ]) |
| self.assertTree(tree) |
| # Test incremental sync: delete-unversioned_trees isn't there. |
| self.parseGclient( |
| ['sync', '--deps', 'mac', '--jobs', '8'], |
| ['running', 'running'], |
| untangle=True) |
| tree = self.mangle_git_tree(('repo_1@2', 'src'), |
| ('repo_2@1', 'src/repo2'), |
| ('repo_3@1', 'src/repo2/repo3'), |
| ('repo_3@2', 'src/repo2/repo_renamed'), |
| ('repo_4@2', 'src/repo4')) |
| tree['src/git_hooked1'] = 'git_hooked1' |
| tree['src/git_hooked2'] = 'git_hooked2' |
| tree['src/repo2/gclient.args'] = '\n'.join([ |
| '# Generated from \'DEPS\'', |
| 'false_var = false', |
| 'false_str_var = false', |
| 'true_var = true', |
| 'true_str_var = true', |
| 'str_var = "abc"', |
| 'cond_var = false', |
| ]) |
| self.assertTree(tree) |
| |
| def testSyncFetch(self): |
| if not self.enabled: |
| return |
| self.gclient(['config', self.git_base + 'repo_13', '--name', 'src']) |
| _out, _err, rc = self.gclient( |
| ['sync', '-v', '-v', '-v', '--revision', self.githash('repo_13', 2)]) |
| self.assertEqual(0, rc) |
| |
| def testSyncFetchUpdate(self): |
| if not self.enabled: |
| return |
| self.gclient(['config', self.git_base + 'repo_13', '--name', 'src']) |
| |
| # Sync to an earlier revision first, one that doesn't refer to |
| # non-standard refs. |
| _out, _err, rc = self.gclient( |
| ['sync', '-v', '-v', '-v', '--revision', self.githash('repo_13', 1)]) |
| self.assertEqual(0, rc) |
| |
| # Make sure update that pulls a non-standard ref works. |
| _out, _err, rc = self.gclient( |
| ['sync', '-v', '-v', '-v', '--revision', self.githash('repo_13', 2)]) |
| self.assertEqual(0, rc) |
| |
| def testSyncDirect(self): |
| if not self.enabled: |
| return |
| self.gclient(['config', self.git_base + 'repo_12', '--name', 'src']) |
| _out, _err, rc = self.gclient( |
| ['sync', '-v', '-v', '-v', '--revision', 'refs/changes/1212']) |
| self.assertEqual(0, rc) |
| |
| def testSyncUnmanaged(self): |
| if not self.enabled: |
| return |
| self.gclient([ |
| 'config', '--spec', |
| 'solutions=[{"name":"src", "url": "%s", "managed": False}]' % ( |
| self.git_base + 'repo_5')]) |
| self.gclient([ |
| 'sync', '--revision', 'src@' + self.githash('repo_5', 2)]) |
| self.gclient([ |
| 'sync', '--revision', 'src/repo1@%s' % self.githash('repo_1', 1)]) |
| # src is unmanaged, so gclient shouldn't have updated it. It should've |
| # stayed synced at @2 |
| tree = self.mangle_git_tree(('repo_5@2', 'src'), |
| ('repo_1@1', 'src/repo1'), |
| ('repo_2@1', 'src/repo2')) |
| tree['src/git_pre_deps_hooked'] = 'git_pre_deps_hooked' |
| self.maxDiff = None |
| self.assertTree(tree) |
| |
| def testSyncUrl(self): |
| if not self.enabled: |
| return |
| self.gclient(['config', self.git_base + 'repo_1', '--name', 'src']) |
| self.gclient([ |
| 'sync', '-v', '-v', '-v', |
| '--revision', 'src/repo2@%s' % self.githash('repo_2', 1), |
| '--revision', '%srepo_2@%s' % (self.git_base, self.githash('repo_2', 2)) |
| ]) |
| # repo_2 should've been synced to @2 instead of @1, since URLs override |
| # paths. |
| tree = self.mangle_git_tree(('repo_1@2', 'src'), |
| ('repo_2@2', 'src/repo2'), |
| ('repo_3@2', 'src/repo2/repo_renamed')) |
| tree['src/git_hooked1'] = 'git_hooked1' |
| tree['src/git_hooked2'] = 'git_hooked2' |
| self.assertTree(tree) |
| |
| def testSyncPatchRef(self): |
| if not self.enabled: |
| return |
| self.gclient(['config', self.git_base + 'repo_1', '--name', 'src']) |
| self.gclient([ |
| 'sync', '-v', '-v', '-v', |
| '--revision', 'src/repo2@%s' % self.githash('repo_2', 1), |
| '--patch-ref', |
| '%srepo_2@refs/heads/master:%s' % ( |
| self.git_base, self.githash('repo_2', 2)), |
| ]) |
| # Assert that repo_2 files coincide with revision @2 (the patch ref) |
| tree = self.mangle_git_tree(('repo_1@2', 'src'), |
| ('repo_2@2', 'src/repo2'), |
| ('repo_3@2', 'src/repo2/repo_renamed')) |
| tree['src/git_hooked1'] = 'git_hooked1' |
| tree['src/git_hooked2'] = 'git_hooked2' |
| self.assertTree(tree) |
| # Assert that HEAD revision of repo_2 is @1 (the base we synced to) since we |
| # should have done a soft reset. |
| self.assertEqual( |
| self.githash('repo_2', 1), |
| self.gitrevparse(os.path.join(self.root_dir, 'src/repo2'))) |
| |
| def testSyncPatchRefNoHooks(self): |
| if not self.enabled: |
| return |
| self.gclient(['config', self.git_base + 'repo_1', '--name', 'src']) |
| self.gclient([ |
| 'sync', '-v', '-v', '-v', |
| '--revision', 'src/repo2@%s' % self.githash('repo_2', 1), |
| '--patch-ref', |
| '%srepo_2@refs/heads/master:%s' % ( |
| self.git_base, self.githash('repo_2', 2)), |
| '--nohooks', |
| ]) |
| # Assert that repo_2 files coincide with revision @2 (the patch ref) |
| tree = self.mangle_git_tree(('repo_1@2', 'src'), |
| ('repo_2@2', 'src/repo2'), |
| ('repo_3@2', 'src/repo2/repo_renamed')) |
| self.assertTree(tree) |
| # Assert that HEAD revision of repo_2 is @1 (the base we synced to) since we |
| # should have done a soft reset. |
| self.assertEqual( |
| self.githash('repo_2', 1), |
| self.gitrevparse(os.path.join(self.root_dir, 'src/repo2'))) |
| |
| def testRunHooks(self): |
| if not self.enabled: |
| return |
| self.gclient(['config', self.git_base + 'repo_1', '--name', 'src']) |
| self.gclient(['sync', '--deps', 'mac']) |
| tree = self.mangle_git_tree(('repo_1@2', 'src'), |
| ('repo_2@1', 'src/repo2'), |
| ('repo_3@2', 'src/repo2/repo_renamed')) |
| tree['src/git_hooked1'] = 'git_hooked1' |
| tree['src/git_hooked2'] = 'git_hooked2' |
| self.assertTree(tree) |
| |
| os.remove(join(self.root_dir, 'src', 'git_hooked1')) |
| os.remove(join(self.root_dir, 'src', 'git_hooked2')) |
| # runhooks runs all hooks even if not matching by design. |
| out = self.parseGclient(['runhooks', '--deps', 'mac'], |
| ['running', 'running']) |
| self.assertEqual(1, len(out[0])) |
| self.assertEqual(1, len(out[1])) |
| tree = self.mangle_git_tree(('repo_1@2', 'src'), |
| ('repo_2@1', 'src/repo2'), |
| ('repo_3@2', 'src/repo2/repo_renamed')) |
| tree['src/git_hooked1'] = 'git_hooked1' |
| tree['src/git_hooked2'] = 'git_hooked2' |
| self.assertTree(tree) |
| |
| def testRunHooksCondition(self): |
| if not self.enabled: |
| return |
| self.gclient(['config', self.git_base + 'repo_7', '--name', 'src']) |
| self.gclient(['sync', '--deps', 'mac']) |
| tree = self.mangle_git_tree(('repo_7@1', 'src')) |
| tree['src/should_run'] = 'should_run' |
| self.assertTree(tree) |
| |
| def testPreDepsHooks(self): |
| if not self.enabled: |
| return |
| self.gclient(['config', self.git_base + 'repo_5', '--name', 'src']) |
| expectation = [ |
| ('running', self.root_dir), # git clone |
| ('running', self.root_dir), # pre-deps hook |
| ] |
| out = self.parseGclient(['sync', '--deps', 'mac', '--jobs=1', |
| '--revision', 'src@' + self.githash('repo_5', 2)], |
| expectation) |
| self.assertEqual('Cloning into ', out[0][1][:13]) |
| self.assertEqual(2, len(out[1]), out[1]) |
| self.assertEqual('pre-deps hook', out[1][1]) |
| tree = self.mangle_git_tree(('repo_5@2', 'src'), |
| ('repo_1@2', 'src/repo1'), |
| ('repo_2@1', 'src/repo2') |
| ) |
| tree['src/git_pre_deps_hooked'] = 'git_pre_deps_hooked' |
| self.assertTree(tree) |
| |
| os.remove(join(self.root_dir, 'src', 'git_pre_deps_hooked')) |
| |
| # Pre-DEPS hooks don't run with runhooks. |
| self.gclient(['runhooks', '--deps', 'mac']) |
| tree = self.mangle_git_tree(('repo_5@2', 'src'), |
| ('repo_1@2', 'src/repo1'), |
| ('repo_2@1', 'src/repo2') |
| ) |
| self.assertTree(tree) |
| |
| # Pre-DEPS hooks run when syncing with --nohooks. |
| self.gclient(['sync', '--deps', 'mac', '--nohooks', |
| '--revision', 'src@' + self.githash('repo_5', 2)]) |
| tree = self.mangle_git_tree(('repo_5@2', 'src'), |
| ('repo_1@2', 'src/repo1'), |
| ('repo_2@1', 'src/repo2') |
| ) |
| tree['src/git_pre_deps_hooked'] = 'git_pre_deps_hooked' |
| self.assertTree(tree) |
| |
| os.remove(join(self.root_dir, 'src', 'git_pre_deps_hooked')) |
| |
| # Pre-DEPS hooks don't run with --noprehooks |
| self.gclient(['sync', '--deps', 'mac', '--noprehooks', |
| '--revision', 'src@' + self.githash('repo_5', 2)]) |
| tree = self.mangle_git_tree(('repo_5@2', 'src'), |
| ('repo_1@2', 'src/repo1'), |
| ('repo_2@1', 'src/repo2') |
| ) |
| self.assertTree(tree) |
| |
| def testPreDepsHooksError(self): |
| if not self.enabled: |
| return |
| self.gclient(['config', self.git_base + 'repo_5', '--name', 'src']) |
| expectated_stdout = [ |
| ('running', self.root_dir), # git clone |
| ('running', self.root_dir), # pre-deps hook |
| ('running', self.root_dir), # pre-deps hook (fails) |
| ] |
| executable = sys.executable |
| # On Python 3 we always execute hooks with 'python', so we cannot use |
| # sys.executable. |
| if sys.version_info.major == 3: |
| executable = subprocess.check_output( |
| ['python', '-c', 'import sys; print(sys.executable)']) |
| executable = executable.decode('utf-8').strip() |
| expected_stderr = ("Error: Command '%s -c import sys; " |
| "sys.exit(1)' returned non-zero exit status 1 in %s\n" |
| % (executable, self.root_dir)) |
| stdout, stderr, retcode = self.gclient(['sync', '--deps', 'mac', '--jobs=1', |
| '--revision', |
| 'src@' + self.githash('repo_5', 3)]) |
| self.assertEqual(stderr, expected_stderr) |
| self.assertEqual(2, retcode) |
| self.checkBlock(stdout, expectated_stdout) |
| |
| def testRevInfo(self): |
| if not self.enabled: |
| return |
| self.gclient(['config', self.git_base + 'repo_1', '--name', 'src']) |
| self.gclient(['sync', '--deps', 'mac']) |
| results = self.gclient(['revinfo', '--deps', 'mac']) |
| out = ('src: %(base)srepo_1\n' |
| 'src/repo2: %(base)srepo_2@%(hash2)s\n' |
| 'src/repo2/repo_renamed: %(base)srepo_3\n' % |
| { |
| 'base': self.git_base, |
| 'hash2': self.githash('repo_2', 1)[:7], |
| }) |
| self.check((out, '', 0), results) |
| |
| def testRevInfoActual(self): |
| if not self.enabled: |
| return |
| self.gclient(['config', self.git_base + 'repo_1', '--name', 'src']) |
| self.gclient(['sync', '--deps', 'mac']) |
| results = self.gclient(['revinfo', '--deps', 'mac', '--actual']) |
| out = ('src: %(base)srepo_1@%(hash1)s\n' |
| 'src/repo2: %(base)srepo_2@%(hash2)s\n' |
| 'src/repo2/repo_renamed: %(base)srepo_3@%(hash3)s\n' % |
| { |
| 'base': self.git_base, |
| 'hash1': self.githash('repo_1', 2), |
| 'hash2': self.githash('repo_2', 1), |
| 'hash3': self.githash('repo_3', 2), |
| }) |
| self.check((out, '', 0), results) |
| |
| def testRevInfoFilterPath(self): |
| if not self.enabled: |
| return |
| self.gclient(['config', self.git_base + 'repo_1', '--name', 'src']) |
| self.gclient(['sync', '--deps', 'mac']) |
| results = self.gclient(['revinfo', '--deps', 'mac', '--filter', 'src']) |
| out = ('src: %(base)srepo_1\n' % |
| { |
| 'base': self.git_base, |
| }) |
| self.check((out, '', 0), results) |
| |
| def testRevInfoFilterURL(self): |
| if not self.enabled: |
| return |
| self.gclient(['config', self.git_base + 'repo_1', '--name', 'src']) |
| self.gclient(['sync', '--deps', 'mac']) |
| results = self.gclient(['revinfo', '--deps', 'mac', |
| '--filter', '%srepo_2' % self.git_base]) |
| out = ('src/repo2: %(base)srepo_2@%(hash2)s\n' % |
| { |
| 'base': self.git_base, |
| 'hash2': self.githash('repo_2', 1)[:7], |
| }) |
| self.check((out, '', 0), results) |
| |
| def testRevInfoFilterURLOrPath(self): |
| if not self.enabled: |
| return |
| self.gclient(['config', self.git_base + 'repo_1', '--name', 'src']) |
| self.gclient(['sync', '--deps', 'mac']) |
| results = self.gclient(['revinfo', '--deps', 'mac', '--filter', 'src', |
| '--filter', '%srepo_2' % self.git_base]) |
| out = ('src: %(base)srepo_1\n' |
| 'src/repo2: %(base)srepo_2@%(hash2)s\n' % |
| { |
| 'base': self.git_base, |
| 'hash2': self.githash('repo_2', 1)[:7], |
| }) |
| self.check((out, '', 0), results) |
| |
| def testRevInfoJsonOutput(self): |
| if not self.enabled: |
| return |
| self.gclient(['config', self.git_base + 'repo_1', '--name', 'src']) |
| self.gclient(['sync', '--deps', 'mac']) |
| output_json = os.path.join(self.root_dir, 'output.json') |
| self.gclient(['revinfo', '--deps', 'mac', '--output-json', output_json]) |
| with open(output_json) as f: |
| output_json = json.load(f) |
| |
| out = { |
| 'src': { |
| 'url': self.git_base + 'repo_1', |
| 'rev': None, |
| }, |
| 'src/repo2': { |
| 'url': self.git_base + 'repo_2', |
| 'rev': self.githash('repo_2', 1)[:7], |
| }, |
| 'src/repo2/repo_renamed': { |
| 'url': self.git_base + 'repo_3', |
| 'rev': None, |
| }, |
| } |
| self.assertEqual(out, output_json) |
| |
| def testRevInfoJsonOutputSnapshot(self): |
| if not self.enabled: |
| return |
| self.gclient(['config', self.git_base + 'repo_1', '--name', 'src']) |
| self.gclient(['sync', '--deps', 'mac']) |
| output_json = os.path.join(self.root_dir, 'output.json') |
| self.gclient(['revinfo', '--deps', 'mac', '--snapshot', |
| '--output-json', output_json]) |
| with open(output_json) as f: |
| output_json = json.load(f) |
| |
| out = [{ |
| 'solution_url': self.git_base + 'repo_1', |
| 'managed': True, |
| 'name': 'src', |
| 'deps_file': 'DEPS', |
| 'custom_deps': { |
| 'src/repo2': '%srepo_2@%s' % ( |
| self.git_base, self.githash('repo_2', 1)), |
| 'src/repo2/repo_renamed': '%srepo_3@%s' % ( |
| self.git_base, self.githash('repo_3', 2)), |
| 'src/should_not_process': None, |
| }, |
| }] |
| self.assertEqual(out, output_json) |
| |
| def testSetDep(self): |
| fake_deps = os.path.join(self.root_dir, 'DEPS.fake') |
| with open(fake_deps, 'w') as f: |
| f.write('\n'.join([ |
| 'vars = { ', |
| ' "foo_var": "foo_val",', |
| ' "foo_rev": "foo_rev",', |
| '}', |
| 'deps = {', |
| ' "foo": {', |
| ' "url": "url@{foo_rev}",', |
| ' },', |
| ' "bar": "url@bar_rev",', |
| '}', |
| ])) |
| |
| results = self.gclient([ |
| 'setdep', '-r', 'foo@new_foo', '-r', 'bar@new_bar', |
| '--var', 'foo_var=new_val', '--deps-file', fake_deps]) |
| |
| with open(fake_deps) as f: |
| contents = f.read().splitlines() |
| |
| self.assertEqual('', results[1], results[1]) |
| self.assertEqual(0, results[2]) |
| self.assertEqual([ |
| 'vars = { ', |
| ' "foo_var": "new_val",', |
| ' "foo_rev": "new_foo",', |
| '}', |
| 'deps = {', |
| ' "foo": {', |
| ' "url": "url@{foo_rev}",', |
| ' },', |
| ' "bar": "url@new_bar",', |
| '}', |
| ], contents) |
| |
| def testSetDep_BuiltinVariables(self): |
| self.gclient(['config', self.git_base + 'repo_1', '--name', 'src']) |
| fake_deps = os.path.join(self.root_dir, 'DEPS.fake') |
| with open(fake_deps, 'w') as f: |
| f.write('\n'.join([ |
| 'vars = { ', |
| ' "foo_var": "foo_val",', |
| ' "foo_rev": "foo_rev",', |
| '}', |
| 'deps = {', |
| ' "foo": {', |
| ' "url": "url@{foo_rev}",', |
| ' },', |
| ' "bar": "url@bar_rev",', |
| '}', |
| 'hooks = [{', |
| ' "name": "uses_builtin_var",', |
| ' "pattern": ".",', |
| ' "action": ["python", "fake.py",', |
| ' "--with-android={checkout_android}"],', |
| '}]', |
| ])) |
| |
| results = self.gclient([ |
| 'setdep', '-r', 'foo@new_foo', '-r', 'bar@new_bar', |
| '--var', 'foo_var=new_val', '--deps-file', fake_deps]) |
| |
| with open(fake_deps) as f: |
| contents = f.read().splitlines() |
| |
| self.assertEqual('', results[1], results[1]) |
| self.assertEqual(0, results[2]) |
| self.assertEqual([ |
| 'vars = { ', |
| ' "foo_var": "new_val",', |
| ' "foo_rev": "new_foo",', |
| '}', |
| 'deps = {', |
| ' "foo": {', |
| ' "url": "url@{foo_rev}",', |
| ' },', |
| ' "bar": "url@new_bar",', |
| '}', |
| 'hooks = [{', |
| ' "name": "uses_builtin_var",', |
| ' "pattern": ".",', |
| ' "action": ["python", "fake.py",', |
| ' "--with-android={checkout_android}"],', |
| '}]', |
| ], contents) |
| |
| def testGetDep(self): |
| fake_deps = os.path.join(self.root_dir, 'DEPS.fake') |
| with open(fake_deps, 'w') as f: |
| f.write('\n'.join([ |
| 'vars = { ', |
| ' "foo_var": "foo_val",', |
| ' "foo_rev": "foo_rev",', |
| '}', |
| 'deps = {', |
| ' "foo": {', |
| ' "url": "url@{foo_rev}",', |
| ' },', |
| ' "bar": "url@bar_rev",', |
| '}', |
| ])) |
| |
| results = self.gclient([ |
| 'getdep', '-r', 'foo', '-r', 'bar','--var', 'foo_var', |
| '--deps-file', fake_deps]) |
| |
| self.assertEqual('', results[1]) |
| self.assertEqual([ |
| 'foo_val', |
| 'foo_rev', |
| 'bar_rev', |
| ], results[0].splitlines()) |
| self.assertEqual(0, results[2]) |
| |
| def testGetDep_BuiltinVariables(self): |
| self.gclient(['config', self.git_base + 'repo_1', '--name', 'src']) |
| fake_deps = os.path.join(self.root_dir, 'DEPS.fake') |
| with open(fake_deps, 'w') as f: |
| f.write('\n'.join([ |
| 'vars = { ', |
| ' "foo_var": "foo_val",', |
| ' "foo_rev": "foo_rev",', |
| '}', |
| 'deps = {', |
| ' "foo": {', |
| ' "url": "url@{foo_rev}",', |
| ' },', |
| ' "bar": "url@bar_rev",', |
| '}', |
| 'hooks = [{', |
| ' "name": "uses_builtin_var",', |
| ' "pattern": ".",', |
| ' "action": ["python", "fake.py",', |
| ' "--with-android={checkout_android}"],', |
| '}]', |
| ])) |
| |
| results = self.gclient([ |
| 'getdep', '-r', 'foo', '-r', 'bar','--var', 'foo_var', |
| '--deps-file', fake_deps]) |
| |
| self.assertEqual('', results[1]) |
| self.assertEqual([ |
| 'foo_val', |
| 'foo_rev', |
| 'bar_rev', |
| ], results[0].splitlines()) |
| self.assertEqual(0, results[2]) |
| |
| def testFlatten(self): |
| if not self.enabled: |
| return |
| |
| output_deps = os.path.join(self.root_dir, 'DEPS.flattened') |
| self.assertFalse(os.path.exists(output_deps)) |
| |
| self.gclient(['config', self.git_base + 'repo_6', '--name', 'src', |
| # This should be ignored because 'custom_true_var' isn't |
| # defined in the DEPS. |
| '--custom-var', 'custom_true_var=True', |
| # This should override 'true_var=True' from the DEPS. |
| '--custom-var', 'true_var="False"']) |
| self.gclient(['sync']) |
| self.gclient(['flatten', '-v', '-v', '-v', '--output-deps', output_deps]) |
| |
| # Assert we can sync to the flattened DEPS we just wrote. |
| solutions = [{ |
| "url": self.git_base + 'repo_6', |
| 'name': 'src', |
| 'deps_file': output_deps |
| }] |
| results = self.gclient([ |
| 'sync', |
| '--spec=solutions=%s' % solutions |
| ]) |
| self.assertEqual(results[2], 0) |
| |
| with open(output_deps) as f: |
| deps_contents = f.read() |
| |
| self.maxDiff = None # pylint: disable=attribute-defined-outside-init |
| self.assertEqual([ |
| 'gclient_gn_args_file = "src/repo2/gclient.args"', |
| 'gclient_gn_args = [\'false_var\', \'false_str_var\', \'true_var\', ' |
| '\'true_str_var\', \'str_var\', \'cond_var\']', |
| 'allowed_hosts = [', |
| ' "' + self.git_base + '",', |
| ']', |
| '', |
| 'deps = {', |
| ' # src -> src/repo2 -> foo/bar', |
| ' "foo/bar": {', |
| ' "url": "' + self.git_base + 'repo_3",', |
| ' "condition": \'(repo2_false_var) and (true_str_var)\',', |
| ' },', |
| '', |
| ' # src', |
| ' "src": {', |
| ' "url": "' + self.git_base + 'repo_6",', |
| ' },', |
| '', |
| ' # src -> src/mac_repo', |
| ' "src/mac_repo": {', |
| ' "url": "' + self.git_base + 'repo_5",', |
| ' "condition": \'checkout_mac\',', |
| ' },', |
| '', |
| ' # src -> src/repo8 -> src/recursed_os_repo', |
| ' "src/recursed_os_repo": {', |
| ' "url": "' + self.git_base + 'repo_5",', |
| ' "condition": \'(checkout_linux) or (checkout_mac)\',', |
| ' },', |
| '', |
| ' # src -> src/repo15', |
| ' "src/repo15": {', |
| ' "url": "' + self.git_base + 'repo_15",', |
| ' },', |
| '', |
| ' # src -> src/repo16', |
| ' "src/repo16": {', |
| ' "url": "' + self.git_base + 'repo_16",', |
| ' },', |
| '', |
| ' # src -> src/repo2', |
| ' "src/repo2": {', |
| ' "url": "' + self.git_base + 'repo_2@%s",' % ( |
| self.githash('repo_2', 1)[:7]), |
| ' "condition": \'true_str_var\',', |
| ' },', |
| '', |
| ' # src -> src/repo4', |
| ' "src/repo4": {', |
| ' "url": "' + self.git_base + 'repo_4",', |
| ' "condition": \'False\',', |
| ' },', |
| '', |
| ' # src -> src/repo8', |
| ' "src/repo8": {', |
| ' "url": "' + self.git_base + 'repo_8",', |
| ' },', |
| '', |
| ' # src -> src/unix_repo', |
| ' "src/unix_repo": {', |
| ' "url": "' + self.git_base + 'repo_5",', |
| ' "condition": \'checkout_linux\',', |
| ' },', |
| '', |
| ' # src -> src/win_repo', |
| ' "src/win_repo": {', |
| ' "url": "' + self.git_base + 'repo_5",', |
| ' "condition": \'checkout_win\',', |
| ' },', |
| '', |
| '}', |
| '', |
| 'hooks = [', |
| ' # src', |
| ' {', |
| ' "pattern": ".",', |
| ' "condition": \'True\',', |
| ' "cwd": ".",', |
| ' "action": [', |
| ' "python",', |
| ' "-c",', |
| ' "open(\'src/git_hooked1\', \'w\')' |
| '.write(\'git_hooked1\')",', |
| ' ]', |
| ' },', |
| '', |
| ' # src', |
| ' {', |
| ' "pattern": "nonexistent",', |
| ' "cwd": ".",', |
| ' "action": [', |
| ' "python",', |
| ' "-c",', |
| ' "open(\'src/git_hooked2\', \'w\').write(\'git_hooked2\')",', |
| ' ]', |
| ' },', |
| '', |
| ' # src', |
| ' {', |
| ' "pattern": ".",', |
| ' "condition": \'checkout_mac\',', |
| ' "cwd": ".",', |
| ' "action": [', |
| ' "python",', |
| ' "-c",', |
| ' "open(\'src/git_hooked_mac\', \'w\').write(' |
| '\'git_hooked_mac\')",', |
| ' ]', |
| ' },', |
| '', |
| ' # src -> src/repo15', |
| ' {', |
| ' "name": "absolute_cwd",', |
| ' "pattern": ".",', |
| ' "cwd": ".",', |
| ' "action": [', |
| ' "python",', |
| ' "-c",', |
| ' "pass",', |
| ' ]', |
| ' },', |
| '', |
| ' # src -> src/repo16', |
| ' {', |
| ' "name": "relative_cwd",', |
| ' "pattern": ".",', |
| ' "cwd": "src/repo16",', |
| ' "action": [', |
| ' "python",', |
| ' "relative.py",', |
| ' ]', |
| ' },', |
| '', |
| ']', |
| '', |
| 'vars = {', |
| ' # src', |
| ' "DummyVariable": \'repo\',', |
| '', |
| ' # src', |
| ' "cond_var": \'false_str_var and true_var\',', |
| '', |
| ' # src', |
| ' "false_str_var": \'False\',', |
| '', |
| ' # src', |
| ' "false_var": False,', |
| '', |
| ' # src', |
| ' "git_base": \'' + self.git_base + '\',', |
| '', |
| ' # src', |
| ' "hook1_contents": \'git_hooked1\',', |
| '', |
| ' # src -> src/repo2', |
| ' "repo2_false_var": \'False\',', |
| '', |
| ' # src', |
| ' "repo5_var": \'/repo_5\',', |
| '', |
| ' # src', |
| ' "str_var": \'abc\',', |
| '', |
| ' # src', |
| ' "true_str_var": \'True\',', |
| '', |
| ' # src [custom_var override]', |
| ' "true_var": \'False\',', |
| '', |
| '}', |
| '', |
| '# ' + self.git_base + 'repo_15, DEPS', |
| '# ' + self.git_base + 'repo_16, DEPS', |
| '# ' + self.git_base + 'repo_2@%s, DEPS' % ( |
| self.githash('repo_2', 1)[:7]), |
| '# ' + self.git_base + 'repo_6, DEPS', |
| '# ' + self.git_base + 'repo_8, DEPS', |
| ], deps_contents.splitlines()) |
| |
| def testFlattenPinAllDeps(self): |
| if not self.enabled: |
| return |
| |
| output_deps = os.path.join(self.root_dir, 'DEPS.flattened') |
| self.assertFalse(os.path.exists(output_deps)) |
| |
| self.gclient(['config', self.git_base + 'repo_6', '--name', 'src']) |
| self.gclient(['sync', '--process-all-deps']) |
| self.gclient(['flatten', '-v', '-v', '-v', '--output-deps', output_deps, |
| '--pin-all-deps']) |
| |
| with open(output_deps) as f: |
| deps_contents = f.read() |
| |
| self.maxDiff = None # pylint: disable=attribute-defined-outside-init |
| self.assertEqual([ |
| 'gclient_gn_args_file = "src/repo2/gclient.args"', |
| 'gclient_gn_args = [\'false_var\', \'false_str_var\', \'true_var\', ' |
| '\'true_str_var\', \'str_var\', \'cond_var\']', |
| 'allowed_hosts = [', |
| ' "' + self.git_base + '",', |
| ']', |
| '', |
| 'deps = {', |
| ' # src -> src/repo2 -> foo/bar', |
| ' "foo/bar": {', |
| ' "url": "' + self.git_base + 'repo_3@%s",' % ( |
| self.githash('repo_3', 2)), |
| ' "condition": \'(repo2_false_var) and (true_str_var)\',', |
| ' },', |
| '', |
| ' # src', |
| ' "src": {', |
| ' "url": "' + self.git_base + 'repo_6@%s",' % ( |
| self.githash('repo_6', 1)), |
| ' },', |
| '', |
| ' # src -> src/mac_repo', |
| ' "src/mac_repo": {', |
| ' "url": "' + self.git_base + 'repo_5@%s",' % ( |
| self.githash('repo_5', 3)), |
| ' "condition": \'checkout_mac\',', |
| ' },', |
| '', |
| ' # src -> src/repo8 -> src/recursed_os_repo', |
| ' "src/recursed_os_repo": {', |
| ' "url": "' + self.git_base + 'repo_5@%s",' % ( |
| self.githash('repo_5', 3)), |
| ' "condition": \'(checkout_linux) or (checkout_mac)\',', |
| ' },', |
| '', |
| ' # src -> src/repo15', |
| ' "src/repo15": {', |
| ' "url": "' + self.git_base + 'repo_15@%s",' % ( |
| self.githash('repo_15', 1)), |
| ' },', |
| '', |
| ' # src -> src/repo16', |
| ' "src/repo16": {', |
| ' "url": "' + self.git_base + 'repo_16@%s",' % ( |
| self.githash('repo_16', 1)), |
| ' },', |
| '', |
| ' # src -> src/repo2', |
| ' "src/repo2": {', |
| ' "url": "' + self.git_base + 'repo_2@%s",' % ( |
| self.githash('repo_2', 1)), |
| ' "condition": \'true_str_var\',', |
| ' },', |
| '', |
| ' # src -> src/repo4', |
| ' "src/repo4": {', |
| ' "url": "' + self.git_base + 'repo_4@%s",' % ( |
| self.githash('repo_4', 2)), |
| ' "condition": \'False\',', |
| ' },', |
| '', |
| ' # src -> src/repo8', |
| ' "src/repo8": {', |
| ' "url": "' + self.git_base + 'repo_8@%s",' % ( |
| self.githash('repo_8', 1)), |
| ' },', |
| '', |
| ' # src -> src/unix_repo', |
| ' "src/unix_repo": {', |
| ' "url": "' + self.git_base + 'repo_5@%s",' % ( |
| self.githash('repo_5', 3)), |
| ' "condition": \'checkout_linux\',', |
| ' },', |
| '', |
| ' # src -> src/win_repo', |
| ' "src/win_repo": {', |
| ' "url": "' + self.git_base + 'repo_5@%s",' % ( |
| self.githash('repo_5', 3)), |
| ' "condition": \'checkout_win\',', |
| ' },', |
| '', |
| '}', |
| '', |
| 'hooks = [', |
| ' # src', |
| ' {', |
| ' "pattern": ".",', |
| ' "condition": \'True\',', |
| ' "cwd": ".",', |
| ' "action": [', |
| ' "python",', |
| ' "-c",', |
| ' "open(\'src/git_hooked1\', \'w\')' |
| '.write(\'git_hooked1\')",', |
| ' ]', |
| ' },', |
| '', |
| ' # src', |
| ' {', |
| ' "pattern": "nonexistent",', |
| ' "cwd": ".",', |
| ' "action": [', |
| ' "python",', |
| ' "-c",', |
| ' "open(\'src/git_hooked2\', \'w\').write(\'git_hooked2\')",', |
| ' ]', |
| ' },', |
| '', |
| ' # src', |
| ' {', |
| ' "pattern": ".",', |
| ' "condition": \'checkout_mac\',', |
| ' "cwd": ".",', |
| ' "action": [', |
| ' "python",', |
| ' "-c",', |
| ' "open(\'src/git_hooked_mac\', \'w\').write(' |
| '\'git_hooked_mac\')",', |
| ' ]', |
| ' },', |
| '', |
| ' # src -> src/repo15', |
| ' {', |
| ' "name": "absolute_cwd",', |
| ' "pattern": ".",', |
| ' "cwd": ".",', |
| ' "action": [', |
| ' "python",', |
| ' "-c",', |
| ' "pass",', |
| ' ]', |
| ' },', |
| '', |
| ' # src -> src/repo16', |
| ' {', |
| ' "name": "relative_cwd",', |
| ' "pattern": ".",', |
| ' "cwd": "src/repo16",', |
| ' "action": [', |
| ' "python",', |
| ' "relative.py",', |
| ' ]', |
| ' },', |
| '', |
| ']', |
| '', |
| 'vars = {', |
| ' # src', |
| ' "DummyVariable": \'repo\',', |
| '', |
| ' # src', |
| ' "cond_var": \'false_str_var and true_var\',', |
| '', |
| ' # src', |
| ' "false_str_var": \'False\',', |
| '', |
| ' # src', |
| ' "false_var": False,', |
| '', |
| ' # src', |
| ' "git_base": \'' + self.git_base + '\',', |
| '', |
| ' # src', |
| ' "hook1_contents": \'git_hooked1\',', |
| '', |
| ' # src -> src/repo2', |
| ' "repo2_false_var": \'False\',', |
| '', |
| ' # src', |
| ' "repo5_var": \'/repo_5\',', |
| '', |
| ' # src', |
| ' "str_var": \'abc\',', |
| '', |
| ' # src', |
| ' "true_str_var": \'True\',', |
| '', |
| ' # src', |
| ' "true_var": True,', |
| '', |
| '}', |
| '', |
| '# ' + self.git_base + 'repo_15@%s, DEPS' % ( |
| self.githash('repo_15', 1)), |
| '# ' + self.git_base + 'repo_16@%s, DEPS' % ( |
| self.githash('repo_16', 1)), |
| '# ' + self.git_base + 'repo_2@%s, DEPS' % ( |
| self.githash('repo_2', 1)), |
| '# ' + self.git_base + 'repo_6@%s, DEPS' % ( |
| self.githash('repo_6', 1)), |
| '# ' + self.git_base + 'repo_8@%s, DEPS' % ( |
| self.githash('repo_8', 1)), |
| ], deps_contents.splitlines()) |
| |
| def testFlattenRecursedeps(self): |
| if not self.enabled: |
| return |
| |
| output_deps = os.path.join(self.root_dir, 'DEPS.flattened') |
| self.assertFalse(os.path.exists(output_deps)) |
| |
| output_deps_files = os.path.join(self.root_dir, 'DEPS.files') |
| self.assertFalse(os.path.exists(output_deps_files)) |
| |
| self.gclient(['config', self.git_base + 'repo_10', '--name', 'src']) |
| self.gclient(['sync', '--process-all-deps']) |
| self.gclient(['flatten', '-v', '-v', '-v', |
| '--output-deps', output_deps, |
| '--output-deps-files', output_deps_files]) |
| |
| with open(output_deps) as f: |
| deps_contents = f.read() |
| |
| self.maxDiff = None |
| self.assertEqual([ |
| 'gclient_gn_args_file = "src/repo2/gclient.args"', |
| "gclient_gn_args = ['str_var']", |
| 'deps = {', |
| ' # src', |
| ' "src": {', |
| ' "url": "' + self.git_base + 'repo_10",', |
| ' },', |
| '', |
| ' # src -> src/repo9 -> src/repo8 -> src/recursed_os_repo', |
| ' "src/recursed_os_repo": {', |
| ' "url": "' + self.git_base + 'repo_5",', |
| ' "condition": \'(checkout_linux) or (checkout_mac)\',', |
| ' },', |
| '', |
| ' # src -> src/repo11', |
| ' "src/repo11": {', |
| ' "url": "' + self.git_base + 'repo_11",', |
| ' "condition": \'(checkout_ios) or (checkout_mac)\',', |
| ' },', |
| '', |
| ' # src -> src/repo11 -> src/repo12', |
| ' "src/repo12": {', |
| ' "url": "' + self.git_base + 'repo_12",', |
| ' "condition": \'(checkout_ios) or (checkout_mac)\',', |
| ' },', |
| '', |
| ' # src -> src/repo9 -> src/repo4', |
| ' "src/repo4": {', |
| ' "url": "' + self.git_base + 'repo_4",', |
| ' "condition": \'checkout_android\',', |
| ' },', |
| '', |
| ' # src -> src/repo6', |
| ' "src/repo6": {', |
| ' "url": "' + self.git_base + 'repo_6",', |
| ' },', |
| '', |
| ' # src -> src/repo9 -> src/repo7', |
| ' "src/repo7": {', |
| ' "url": "' + self.git_base + 'repo_7",', |
| ' },', |
| '', |
| ' # src -> src/repo9 -> src/repo8', |
| ' "src/repo8": {', |
| ' "url": "' + self.git_base + 'repo_8",', |
| ' },', |
| '', |
| ' # src -> src/repo9', |
| ' "src/repo9": {', |
| ' "url": "' + self.git_base + 'repo_9",', |
| ' },', |
| '', |
| '}', |
| '', |
| 'vars = {', |
| ' # src -> src/repo9', |
| ' "str_var": \'xyz\',', |
| '', |
| '}', |
| '', |
| '# ' + self.git_base + 'repo_10, DEPS', |
| '# ' + self.git_base + 'repo_11, DEPS', |
| '# ' + self.git_base + 'repo_8, DEPS', |
| '# ' + self.git_base + 'repo_9, DEPS', |
| ], deps_contents.splitlines()) |
| |
| with open(output_deps_files) as f: |
| deps_files_contents = json.load(f) |
| |
| self.assertEqual([ |
| {'url': self.git_base + 'repo_10', 'deps_file': 'DEPS', |
| 'hierarchy': [['src', self.git_base + 'repo_10']]}, |
| {'url': self.git_base + 'repo_11', 'deps_file': 'DEPS', |
| 'hierarchy': [['src', self.git_base + 'repo_10'], |
| ['src/repo11', self.git_base + 'repo_11']]}, |
| {'url': self.git_base + 'repo_8', 'deps_file': 'DEPS', |
| 'hierarchy': [['src', self.git_base + 'repo_10'], |
| ['src/repo9', self.git_base + 'repo_9'], |
| ['src/repo8', self.git_base + 'repo_8']]}, |
| {'url': self.git_base + 'repo_9', 'deps_file': 'DEPS', |
| 'hierarchy': [['src', self.git_base + 'repo_10'], |
| ['src/repo9', self.git_base + 'repo_9']]}, |
| ], deps_files_contents) |
| |
| def testFlattenCipd(self): |
| if not self.enabled: |
| return |
| |
| output_deps = os.path.join(self.root_dir, 'DEPS.flattened') |
| self.assertFalse(os.path.exists(output_deps)) |
| |
| self.gclient(['config', self.git_base + 'repo_14', '--name', 'src']) |
| self.gclient(['sync']) |
| self.gclient(['flatten', '-v', '-v', '-v', '--output-deps', output_deps]) |
| |
| with open(output_deps) as f: |
| deps_contents = f.read() |
| |
| self.maxDiff = None # pylint: disable=attribute-defined-outside-init |
| self.assertEqual([ |
| 'deps = {', |
| ' # src', |
| ' "src": {', |
| ' "url": "' + self.git_base + 'repo_14",', |
| ' },', |
| '', |
| ' # src -> src/another_cipd_dep', |
| ' "src/another_cipd_dep": {', |
| ' "packages": [', |
| ' {', |
| ' "package": "package1",', |
| ' "version": "1.1-cr0",', |
| ' },', |
| ' {', |
| ' "package": "package2",', |
| ' "version": "1.13",', |
| ' },', |
| ' ],', |
| ' "dep_type": "cipd",', |
| ' },', |
| '', |
| ' # src -> src/cipd_dep', |
| ' "src/cipd_dep": {', |
| ' "packages": [', |
| ' {', |
| ' "package": "package0",', |
| ' "version": "0.1",', |
| ' },', |
| ' ],', |
| ' "dep_type": "cipd",', |
| ' },', |
| '', |
| ' # src -> src/cipd_dep_with_cipd_variable', |
| ' "src/cipd_dep_with_cipd_variable": {', |
| ' "packages": [', |
| ' {', |
| ' "package": "package3/${{platform}}",', |
| ' "version": "1.2",', |
| ' },', |
| ' ],', |
| ' "dep_type": "cipd",', |
| ' },', |
| '', |
| '}', |
| '', |
| '# ' + self.git_base + 'repo_14, DEPS', |
| ], deps_contents.splitlines()) |
| |
| |
| class GClientSmokeGITMutates(GClientSmokeBase): |
| """testRevertAndStatus mutates the git repo so move it to its own suite.""" |
| def setUp(self): |
| super(GClientSmokeGITMutates, self).setUp() |
| self.enabled = self.FAKE_REPOS.set_up_git() |
| |
| def testRevertAndStatus(self): |
| if not self.enabled: |
| return |
| |
| # Commit new change to repo to make repo_2's hash use a custom_var. |
| cur_deps = self.FAKE_REPOS.git_hashes['repo_1'][-1][1]['DEPS'] |
| repo_2_hash = self.FAKE_REPOS.git_hashes['repo_2'][1][0][:7] |
| new_deps = cur_deps.replace('repo_2@%s\'' % repo_2_hash, |
| 'repo_2@\' + Var(\'r2hash\')') |
| new_deps = 'vars = {\'r2hash\': \'%s\'}\n%s' % (repo_2_hash, new_deps) |
| self.FAKE_REPOS._commit_git('repo_1', { # pylint: disable=protected-access |
| 'DEPS': new_deps, |
| 'origin': 'git/repo_1@3\n', |
| }) |
| |
| config_template = ( |
| """solutions = [{ |
| "name" : "src", |
| "url" : "%(git_base)srepo_1", |
| "deps_file" : "DEPS", |
| "managed" : True, |
| "custom_vars" : %(custom_vars)s, |
| }]""") |
| |
| self.gclient(['config', '--spec', config_template % { |
| 'git_base': self.git_base, |
| 'custom_vars': {} |
| }]) |
| |
| # Tested in testSync. |
| self.gclient(['sync', '--deps', 'mac']) |
| write(join(self.root_dir, 'src', 'repo2', 'hi'), 'Hey!') |
| |
| out = self.parseGclient(['status', '--deps', 'mac', '--jobs', '1'], []) |
| # TODO(maruel): http://crosbug.com/3584 It should output the unversioned |
| # files. |
| self.assertEqual(0, len(out)) |
| |
| # Revert implies --force implies running hooks without looking at pattern |
| # matching. For each expected path, 'git reset' and 'git clean' are run, so |
| # there should be two results for each. The last two results should reflect |
| # writing git_hooked1 and git_hooked2. There's only one result for the third |
| # because it is clean and has no output for 'git clean'. |
| out = self.parseGclient(['revert', '--deps', 'mac', '--jobs', '1'], |
| ['running', 'running']) |
| self.assertEqual(2, len(out)) |
| tree = self.mangle_git_tree(('repo_1@3', 'src'), |
| ('repo_2@1', 'src/repo2'), |
| ('repo_3@2', 'src/repo2/repo_renamed')) |
| tree['src/git_hooked1'] = 'git_hooked1' |
| tree['src/git_hooked2'] = 'git_hooked2' |
| self.assertTree(tree) |
| |
| # Make a new commit object in the origin repo, to force reset to fetch. |
| self.FAKE_REPOS._commit_git('repo_2', { # pylint: disable=protected-access |
| 'origin': 'git/repo_2@3\n', |
| }) |
| |
| self.gclient(['config', '--spec', config_template % { |
| 'git_base': self.git_base, |
| 'custom_vars': {'r2hash': self.FAKE_REPOS.git_hashes['repo_2'][-1][0] } |
| }]) |
| out = self.parseGclient(['revert', '--deps', 'mac', '--jobs', '1'], |
| ['running', 'running']) |
| self.assertEqual(2, len(out)) |
| tree = self.mangle_git_tree(('repo_1@3', 'src'), |
| ('repo_2@3', 'src/repo2'), |
| ('repo_3@2', 'src/repo2/repo_renamed')) |
| tree['src/git_hooked1'] = 'git_hooked1' |
| tree['src/git_hooked2'] = 'git_hooked2' |
| self.assertTree(tree) |
| |
| results = self.gclient(['status', '--deps', 'mac', '--jobs', '1']) |
| out = results[0].splitlines(False) |
| # TODO(maruel): http://crosbug.com/3584 It should output the unversioned |
| # files. |
| self.assertEqual(0, len(out)) |
| |
| def testSyncNoHistory(self): |
| if not self.enabled: |
| return |
| # Create an extra commit in repo_2 and point DEPS to its hash. |
| cur_deps = self.FAKE_REPOS.git_hashes['repo_1'][-1][1]['DEPS'] |
| repo_2_hash_old = self.FAKE_REPOS.git_hashes['repo_2'][1][0][:7] |
| self.FAKE_REPOS._commit_git('repo_2', { # pylint: disable=protected-access |
| 'last_file': 'file created in last commit', |
| }) |
| repo_2_hash_new = self.FAKE_REPOS.git_hashes['repo_2'][-1][0] |
| new_deps = cur_deps.replace(repo_2_hash_old, repo_2_hash_new) |
| self.assertNotEqual(new_deps, cur_deps) |
| self.FAKE_REPOS._commit_git('repo_1', { # pylint: disable=protected-access |
| 'DEPS': new_deps, |
| 'origin': 'git/repo_1@4\n', |
| }) |
| |
| config_template = ( |
| """solutions = [{ |
| "name" : "src", |
| "url" : "%(git_base)srepo_1", |
| "deps_file" : "DEPS", |
| "managed" : True, |
| }]""") |
| |
| self.gclient(['config', '--spec', config_template % { |
| 'git_base': self.git_base |
| }]) |
| |
| self.gclient(['sync', '--no-history', '--deps', 'mac']) |
| repo2_root = join(self.root_dir, 'src', 'repo2') |
| |
| # Check that repo_2 is actually shallow and its log has only one entry. |
| rev_lists = subprocess2.check_output(['git', 'rev-list', 'HEAD'], |
| cwd=repo2_root).decode('utf-8') |
| self.assertEqual(repo_2_hash_new, rev_lists.strip('\r\n')) |
| |
| # Check that we have actually checked out the right commit. |
| self.assertTrue(os.path.exists(join(repo2_root, 'last_file'))) |
| |
| |
| class SkiaDEPSTransitionSmokeTest(GClientSmokeBase): |
| """Simulate the behavior of bisect bots as they transition across the Skia |
| DEPS change.""" |
| |
| FAKE_REPOS_CLASS = fake_repos.FakeRepoSkiaDEPS |
| |
| def setUp(self): |
| super(SkiaDEPSTransitionSmokeTest, self).setUp() |
| self.enabled = self.FAKE_REPOS.set_up_git() |
| |
| def testSkiaDEPSChangeGit(self): |
| if not self.enabled: |
| return |
| |
| # Create an initial checkout: |
| # - Single checkout at the root. |
| # - Multiple checkouts in a shared subdirectory. |
| self.gclient(['config', '--spec', |
| 'solutions=[' |
| '{"name": "src",' |
| ' "url": "' + self.git_base + 'repo_2",' |
| '}]']) |
| |
| checkout_path = os.path.join(self.root_dir, 'src') |
| skia = os.path.join(checkout_path, 'third_party', 'skia') |
| skia_gyp = os.path.join(skia, 'gyp') |
| skia_include = os.path.join(skia, 'include') |
| skia_src = os.path.join(skia, 'src') |
| |
| gyp_git_url = self.git_base + 'repo_3' |
| include_git_url = self.git_base + 'repo_4' |
| src_git_url = self.git_base + 'repo_5' |
| skia_git_url = self.FAKE_REPOS.git_base + 'repo_1' |
| |
| pre_hash = self.githash('repo_2', 1) |
| post_hash = self.githash('repo_2', 2) |
| |
| # Initial sync. Verify that we get the expected checkout. |
| res = self.gclient(['sync', '--deps', 'mac', '--revision', |
| 'src@%s' % pre_hash]) |
| self.assertEqual(res[2], 0, 'Initial sync failed.') |
| self.assertEqual(gclient_scm.GIT.Capture(['config', 'remote.origin.url'], |
| skia_gyp), gyp_git_url) |
| self.assertEqual(gclient_scm.GIT.Capture(['config', 'remote.origin.url'], |
| skia_include), include_git_url) |
| self.assertEqual(gclient_scm.GIT.Capture(['config', 'remote.origin.url'], |
| skia_src), src_git_url) |
| |
| # Verify that the sync succeeds. Verify that we have the expected merged |
| # checkout. |
| res = self.gclient(['sync', '--deps', 'mac', '--revision', |
| 'src@%s' % post_hash]) |
| self.assertEqual(res[2], 0, 'DEPS change sync failed.') |
| self.assertEqual(gclient_scm.GIT.Capture(['config', 'remote.origin.url'], |
| skia), skia_git_url) |
| |
| # Sync again. Verify that we still have the expected merged checkout. |
| res = self.gclient(['sync', '--deps', 'mac', '--revision', |
| 'src@%s' % post_hash]) |
| self.assertEqual(res[2], 0, 'Subsequent sync failed.') |
| self.assertEqual(gclient_scm.GIT.Capture(['config', 'remote.origin.url'], |
| skia), skia_git_url) |
| |
| # Sync back to the original DEPS. Verify that we get the original structure. |
| res = self.gclient(['sync', '--deps', 'mac', '--revision', |
| 'src@%s' % pre_hash]) |
| self.assertEqual(res[2], 0, 'Reverse sync failed.') |
| self.assertEqual(gclient_scm.GIT.Capture(['config', 'remote.origin.url'], |
| skia_gyp), gyp_git_url) |
| self.assertEqual(gclient_scm.GIT.Capture(['config', 'remote.origin.url'], |
| skia_include), include_git_url) |
| self.assertEqual(gclient_scm.GIT.Capture(['config', 'remote.origin.url'], |
| skia_src), src_git_url) |
| |
| # Sync again. Verify that we still have the original structure. |
| res = self.gclient(['sync', '--deps', 'mac', '--revision', |
| 'src@%s' % pre_hash]) |
| self.assertEqual(res[2], 0, 'Subsequent sync #2 failed.') |
| self.assertEqual(gclient_scm.GIT.Capture(['config', 'remote.origin.url'], |
| skia_gyp), gyp_git_url) |
| self.assertEqual(gclient_scm.GIT.Capture(['config', 'remote.origin.url'], |
| skia_include), include_git_url) |
| self.assertEqual(gclient_scm.GIT.Capture(['config', 'remote.origin.url'], |
| skia_src), src_git_url) |
| |
| |
| class BlinkDEPSTransitionSmokeTest(GClientSmokeBase): |
| """Simulate the behavior of bisect bots as they transition across the Blink |
| DEPS change.""" |
| |
| FAKE_REPOS_CLASS = fake_repos.FakeRepoBlinkDEPS |
| |
| def setUp(self): |
| super(BlinkDEPSTransitionSmokeTest, self).setUp() |
| self.enabled = self.FAKE_REPOS.set_up_git() |
| self.checkout_path = os.path.join(self.root_dir, 'src') |
| self.blink = os.path.join(self.checkout_path, 'third_party', 'WebKit') |
| self.blink_git_url = self.FAKE_REPOS.git_base + 'repo_2' |
| self.pre_merge_sha = self.githash('repo_1', 1) |
| self.post_merge_sha = self.githash('repo_1', 2) |
| |
| def CheckStatusPreMergePoint(self): |
| self.assertEqual(gclient_scm.GIT.Capture(['config', 'remote.origin.url'], |
| self.blink), self.blink_git_url) |
| self.assertTrue(os.path.exists(join(self.blink, '.git'))) |
| self.assertTrue(os.path.exists(join(self.blink, 'OWNERS'))) |
| with open(join(self.blink, 'OWNERS')) as f: |
| owners_content = f.read() |
| self.assertEqual('OWNERS-pre', owners_content, 'OWNERS not updated') |
| self.assertTrue(os.path.exists(join(self.blink, 'Source', 'exists_always'))) |
| self.assertTrue(os.path.exists( |
| join(self.blink, 'Source', 'exists_before_but_not_after'))) |
| self.assertFalse(os.path.exists( |
| join(self.blink, 'Source', 'exists_after_but_not_before'))) |
| |
| def CheckStatusPostMergePoint(self): |
| # Check that the contents still exists |
| self.assertTrue(os.path.exists(join(self.blink, 'OWNERS'))) |
| with open(join(self.blink, 'OWNERS')) as f: |
| owners_content = f.read() |
| self.assertEqual('OWNERS-post', owners_content, 'OWNERS not updated') |
| self.assertTrue(os.path.exists(join(self.blink, 'Source', 'exists_always'))) |
| # Check that file removed between the branch point are actually deleted. |
| self.assertTrue(os.path.exists( |
| join(self.blink, 'Source', 'exists_after_but_not_before'))) |
| self.assertFalse(os.path.exists( |
| join(self.blink, 'Source', 'exists_before_but_not_after'))) |
| # But not the .git folder |
| self.assertFalse(os.path.exists(join(self.blink, '.git'))) |
| |
| @unittest.skip('flaky') |
| def testBlinkDEPSChangeUsingGclient(self): |
| """Checks that {src,blink} repos are consistent when syncing going back and |
| forth using gclient sync src@revision.""" |
| if not self.enabled: |
| return |
| |
| self.gclient(['config', '--spec', |
| 'solutions=[' |
| '{"name": "src",' |
| ' "url": "' + self.git_base + 'repo_1",' |
| '}]']) |
| |
| # Go back and forth two times. |
| for _ in range(2): |
| res = self.gclient(['sync', '--jobs', '1', |
| '--revision', 'src@%s' % self.pre_merge_sha]) |
| self.assertEqual(res[2], 0, 'DEPS change sync failed.') |
| self.CheckStatusPreMergePoint() |
| |
| res = self.gclient(['sync', '--jobs', '1', |
| '--revision', 'src@%s' % self.post_merge_sha]) |
| self.assertEqual(res[2], 0, 'DEPS change sync failed.') |
| self.CheckStatusPostMergePoint() |
| |
| |
| @unittest.skip('flaky') |
| def testBlinkDEPSChangeUsingGit(self): |
| """Like testBlinkDEPSChangeUsingGclient, but move the main project using |
| directly git and not gclient sync.""" |
| if not self.enabled: |
| return |
| |
| self.gclient(['config', '--spec', |
| 'solutions=[' |
| '{"name": "src",' |
| ' "url": "' + self.git_base + 'repo_1",' |
| ' "managed": False,' |
| '}]']) |
| |
| # Perform an initial sync to bootstrap the repo. |
| res = self.gclient(['sync', '--jobs', '1']) |
| self.assertEqual(res[2], 0, 'Initial gclient sync failed.') |
| |
| # Go back and forth two times. |
| for _ in range(2): |
| subprocess2.check_call(['git', 'checkout', '-q', self.pre_merge_sha], |
| cwd=self.checkout_path) |
| res = self.gclient(['sync', '--jobs', '1']) |
| self.assertEqual(res[2], 0, 'gclient sync failed.') |
| self.CheckStatusPreMergePoint() |
| |
| subprocess2.check_call(['git', 'checkout', '-q', self.post_merge_sha], |
| cwd=self.checkout_path) |
| res = self.gclient(['sync', '--jobs', '1']) |
| self.assertEqual(res[2], 0, 'DEPS change sync failed.') |
| self.CheckStatusPostMergePoint() |
| |
| |
| @unittest.skip('flaky') |
| def testBlinkLocalBranchesArePreserved(self): |
| """Checks that the state of local git branches are effectively preserved |
| when going back and forth.""" |
| if not self.enabled: |
| return |
| |
| self.gclient(['config', '--spec', |
| 'solutions=[' |
| '{"name": "src",' |
| ' "url": "' + self.git_base + 'repo_1",' |
| '}]']) |
| |
| # Initialize to pre-merge point. |
| self.gclient(['sync', '--revision', 'src@%s' % self.pre_merge_sha]) |
| self.CheckStatusPreMergePoint() |
| |
| # Create a branch named "foo". |
| subprocess2.check_call(['git', 'checkout', '-qB', 'foo'], |
| cwd=self.blink) |
| |
| # Cross the pre-merge point. |
| self.gclient(['sync', '--revision', 'src@%s' % self.post_merge_sha]) |
| self.CheckStatusPostMergePoint() |
| |
| # Go backwards and check that we still have the foo branch. |
| self.gclient(['sync', '--revision', 'src@%s' % self.pre_merge_sha]) |
| self.CheckStatusPreMergePoint() |
| subprocess2.check_call( |
| ['git', 'show-ref', '-q', '--verify', 'refs/heads/foo'], cwd=self.blink) |
| |
| |
| class GClientSmokeCipd(GClientSmokeBase): |
| def setUp(self): |
| super(GClientSmokeCipd, self).setUp() |
| self.enabled = self.FAKE_REPOS.set_up_git() |
| self.env['PATH'] = (os.path.join(ROOT_DIR, 'testing_support') |
| + os.pathsep + self.env['PATH']) |
| |
| def testSyncCipd(self): |
| self.gclient(['config', self.git_base + 'repo_14', '--name', 'src']) |
| out, err, rc = self.gclient(['sync']) |
| self.assertEqual(0, rc, out + err) |
| |
| tree = self.mangle_git_tree(('repo_14@1', 'src')) |
| tree.update({ |
| '_cipd': '\n'.join([ |
| '$ParanoidMode CheckPresence', |
| '', |
| '@Subdir src/another_cipd_dep', |
| 'package1 1.1-cr0', |
| 'package2 1.13', |
| '', |
| '@Subdir src/cipd_dep', |
| 'package0 0.1', |
| '', |
| '@Subdir src/cipd_dep_with_cipd_variable', |
| 'package3/${platform} 1.2', |
| '', |
| '', |
| ]), |
| 'src/another_cipd_dep/_cipd': '\n'.join([ |
| 'package1 1.1-cr0', |
| 'package2 1.13', |
| ]), |
| 'src/cipd_dep/_cipd': 'package0 0.1', |
| 'src/cipd_dep_with_cipd_variable/_cipd': 'package3/${platform} 1.2', |
| }) |
| self.assertTree(tree) |
| |
| def testConvertGitToCipd(self): |
| self.gclient(['config', self.git_base + 'repo_13', '--name', 'src']) |
| |
| # repo_13@1 has src/repo12 as a git dependency. |
| out, err, rc = self.gclient( |
| ['sync', '-v', '-v', '-v', '--revision', self.githash('repo_13', 1)]) |
| self.assertEqual(0, rc, out + err) |
| |
| tree = self.mangle_git_tree(('repo_13@1', 'src'), |
| ('repo_12@1', 'src/repo12')) |
| self.assertTree(tree) |
| |
| # repo_13@3 has src/repo12 as a cipd dependency. |
| out, err, rc = self.gclient( |
| ['sync', '-v', '-v', '-v', '--revision', self.githash('repo_13', 3), |
| '--delete_unversioned_trees']) |
| self.assertEqual(0, rc, out + err) |
| |
| tree = self.mangle_git_tree(('repo_13@3', 'src')) |
| tree.update({ |
| '_cipd': '\n'.join([ |
| '$ParanoidMode CheckPresence', |
| '', |
| '@Subdir src/repo12', |
| 'foo 1.3', |
| '', |
| '', |
| ]), |
| 'src/repo12/_cipd': 'foo 1.3', |
| }) |
| self.assertTree(tree) |
| |
| def testConvertCipdToGit(self): |
| self.gclient(['config', self.git_base + 'repo_13', '--name', 'src']) |
| |
| # repo_13@3 has src/repo12 as a cipd dependency. |
| out, err, rc = self.gclient( |
| ['sync', '-v', '-v', '-v', '--revision', self.githash('repo_13', 3), |
| '--delete_unversioned_trees']) |
| self.assertEqual(0, rc, out + err) |
| |
| tree = self.mangle_git_tree(('repo_13@3', 'src')) |
| tree.update({ |
| '_cipd': '\n'.join([ |
| '$ParanoidMode CheckPresence', |
| '', |
| '@Subdir src/repo12', |
| 'foo 1.3', |
| '', |
| '', |
| ]), |
| 'src/repo12/_cipd': 'foo 1.3', |
| }) |
| self.assertTree(tree) |
| |
| # repo_13@1 has src/repo12 as a git dependency. |
| out, err, rc = self.gclient( |
| ['sync', '-v', '-v', '-v', '--revision', self.githash('repo_13', 1)]) |
| self.assertEqual(0, rc, out + err) |
| |
| tree = self.mangle_git_tree(('repo_13@1', 'src'), |
| ('repo_12@1', 'src/repo12')) |
| tree.update({ |
| '_cipd': '\n'.join([ |
| '$ParanoidMode CheckPresence', |
| '', |
| '@Subdir src/repo12', |
| 'foo 1.3', |
| '', |
| '', |
| ]), |
| 'src/repo12/_cipd': 'foo 1.3', |
| }) |
| self.assertTree(tree) |
| |
| |
| if __name__ == '__main__': |
| if '-v' in sys.argv: |
| logging.basicConfig(level=logging.DEBUG) |
| |
| if '-c' in sys.argv: |
| COVERAGE = True |
| sys.argv.remove('-c') |
| if os.path.exists('.coverage'): |
| os.remove('.coverage') |
| os.environ['COVERAGE_FILE'] = os.path.join( |
| os.path.dirname(os.path.dirname(os.path.abspath(__file__))), |
| '.coverage') |
| unittest.main() |