Commit 7d1655b8 authored by Edward Lesmes's avatar Edward Lesmes Committed by LUCI CQ

depot_tools: Split gclient_smoketests.

gclient_smoketest takes the longest to run among all tests.
Split it so that presubmit takes less time overall, and is
less likely to exceed the time limit.

Change-Id: I5a4f714b98f59a2e46bae944a043ad41b6786c25
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/2121154Reviewed-by: 's avatarJosip Sokcevic <sokcevic@google.com>
Commit-Queue: Edward Lesmes <ehmaldonado@chromium.org>
parent 4c3eb703
#!/usr/bin/env vpython3
# Copyright (c) 2020 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 cipd tests.
"""
import logging
import os
import sys
import unittest
import gclient_smoketest_base
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
class GClientSmokeCipd(gclient_smoketest_base.GClientSmokeBase):
def setUp(self):
super(GClientSmokeCipd, self).setUp()
self.enabled = self.FAKE_REPOS.set_up_git()
if not self.enabled:
self.skipTest('git fake repos not available')
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'])
self.gclient(['sync'])
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.
self.gclient(
['sync', '-v', '-v', '-v', '--revision', self.githash('repo_13', 1)])
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.
self.gclient(
['sync', '-v', '-v', '-v', '--revision', self.githash('repo_13', 3),
'--delete_unversioned_trees'])
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.
self.gclient(
['sync', '-v', '-v', '-v', '--revision', self.githash('repo_13', 3),
'--delete_unversioned_trees'])
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.
self.gclient(
['sync', '-v', '-v', '-v', '--revision', self.githash('repo_13', 1)])
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)
unittest.main()
#!/usr/bin/env vpython3
# Copyright (c) 2020 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 git tests.
"""
import json
import logging
import os
import sys
import unittest
import gclient_smoketest_base
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, ROOT_DIR)
import subprocess2
from testing_support.fake_repos import join, write
class GClientSmokeGITMutates(gclient_smoketest_base.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()
if not self.enabled:
self.skipTest('git fake repos not available')
# TODO(crbug.com/1024683): Enable for windows.
@unittest.skipIf(sys.platform == 'win32', 'not yet fixed on win')
def testRevertAndStatus(self):
# 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 = ''.join([
'solutions = [{'
' "name" : "src",'
' "url" : %(git_base)r + "repo_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):
# 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 = ''.join([
'solutions = [{'
' "name" : "src",'
' "url" : %(git_base)r + "repo_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 GClientSmokeGIT(gclient_smoketest_base.GClientSmokeBase):
def setUp(self):
super(GClientSmokeGIT, self).setUp()
self.env['PATH'] = (os.path.join(ROOT_DIR, 'testing_support')
+ os.pathsep + self.env['PATH'])
self.enabled = self.FAKE_REPOS.set_up_git()
if not self.enabled:
self.skipTest('git fake repos not available')
def testSync(self):
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)
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."""
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):
# 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):
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):
self.gclient(['config', self.git_base + 'repo_13', '--name', 'src'])
self.gclient(
['sync', '-v', '-v', '-v', '--revision', self.githash('repo_13', 2)])
def testSyncFetchUpdate(self):
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.
self.gclient(
['sync', '-v', '-v', '-v', '--revision', self.githash('repo_13', 1)])
# Make sure update that pulls a non-standard ref works.
self.gclient(
['sync', '-v', '-v', '-v', '--revision', self.githash('repo_13', 2)])
def testSyncDirect(self):
self.gclient(['config', self.git_base + 'repo_12', '--name', 'src'])
self.gclient(
['sync', '-v', '-v', '-v', '--revision', 'refs/changes/1212'])
def testSyncUnmanaged(self):
self.gclient([
'config', '--spec',
'solutions=[{"name":"src", "url": %r, "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.assertTree(tree)
def testSyncUrl(self):
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):
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):
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):
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):
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):
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):
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)
]
vpython = 'vpython.bat' if sys.platform == 'win32' else 'vpython'
expected_stderr = ("Error: Command '%s -c import sys; "
"sys.exit(1)' returned non-zero exit status 1 in %s\n"
% (vpython, self.root_dir))
stdout, stderr, retcode = self.gclient(
['sync', '--deps', 'mac', '--jobs=1', '--revision',
'src@' + self.githash('repo_5', 3)], error_ok=True)
self.assertEqual(stderr, expected_stderr)
self.assertEqual(2, retcode)
self.checkBlock(stdout, expectated_stdout)
def testRevInfo(self):
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):
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):
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):
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):
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):
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):
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",',
'}',
]))
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([
'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}"],',
'}]',
]))
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([
'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([
'foo_val',
'foo_rev',
'bar_rev',
], results[0].splitlines())
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([
'foo_val',
'foo_rev',
'bar_rev',
], results[0].splitlines())
# TODO(crbug.com/1024683): Enable for windows.
@unittest.skipIf(sys.platform == 'win32', 'not yet fixed on win')
def testFlatten(self):
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
}]
self.gclient([
'sync',
'--spec=solutions=%s' % solutions
])
with open(output_deps) as f:
deps_contents = f.read()
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())
# TODO(crbug.com/1024683): Enable for windows.
@unittest.skipIf(sys.platform == 'win32', 'not yet fixed on win')
def testFlattenPinAllDeps(self):
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.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())
# TODO(crbug.com/1024683): Enable for windows.
@unittest.skipIf(sys.platform == 'win32', 'not yet fixed on win')
def testFlattenRecursedeps(self):
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.assertEqual([
'gclient_gn_args_file = "src/repo8/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)
# TODO(crbug.com/1024683): Enable for windows.
@unittest.skipIf(sys.platform == 'win32', 'not yet fixed on win')
def testFlattenCipd(self):
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.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())
if __name__ == '__main__':
if '-v' in sys.argv:
logging.basicConfig(level=logging.DEBUG)
unittest.main()
......@@ -6,166 +6,23 @@
"""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
import gclient_smoketest_base
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'
# Suppress Python 3 warnings and other test undesirables.
self.env['GCLIENT_TEST'] = '1'
self.maxDiff = None
def gclient(self, cmd, cwd=None, error_ok=False):
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))
if not error_ok:
self.assertEqual(0, process.returncode, 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, _) = self.gclient(cmd)
if untangle:
stdout = self.untangle(stdout)
self.checkString(expected_stderr, stderr)
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):
class GClientSmoke(gclient_smoketest_base.GClientSmokeBase):
"""Doesn't require git-daemon."""
@property
def git_base(self):
......@@ -309,1713 +166,7 @@ class GClientSmoke(GClientSmokeBase):
self.checkBlock(res[0], [('running', deps), ('running', src)])
class GClientSmokeGIT(GClientSmokeBase):
def setUp(self):
super(GClientSmokeGIT, self).setUp()
self.env['PATH'] = (os.path.join(ROOT_DIR, 'testing_support')
+ os.pathsep + self.env['PATH'])
self.enabled = self.FAKE_REPOS.set_up_git()
if not self.enabled:
self.skipTest('git fake repos not available')
def testSync(self):
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)
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."""
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):
# 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):
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):
self.gclient(['config', self.git_base + 'repo_13', '--name', 'src'])
self.gclient(
['sync', '-v', '-v', '-v', '--revision', self.githash('repo_13', 2)])
def testSyncFetchUpdate(self):
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.
self.gclient(
['sync', '-v', '-v', '-v', '--revision', self.githash('repo_13', 1)])
# Make sure update that pulls a non-standard ref works.
self.gclient(
['sync', '-v', '-v', '-v', '--revision', self.githash('repo_13', 2)])
def testSyncDirect(self):
self.gclient(['config', self.git_base + 'repo_12', '--name', 'src'])
self.gclient(
['sync', '-v', '-v', '-v', '--revision', 'refs/changes/1212'])
def testSyncUnmanaged(self):
self.gclient([
'config', '--spec',
'solutions=[{"name":"src", "url": %r, "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.assertTree(tree)
def testSyncUrl(self):
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):
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):
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):
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):
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):
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):
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)
]
vpython = 'vpython.bat' if sys.platform == 'win32' else 'vpython'
expected_stderr = ("Error: Command '%s -c import sys; "
"sys.exit(1)' returned non-zero exit status 1 in %s\n"
% (vpython, self.root_dir))
stdout, stderr, retcode = self.gclient(
['sync', '--deps', 'mac', '--jobs=1', '--revision',
'src@' + self.githash('repo_5', 3)], error_ok=True)
self.assertEqual(stderr, expected_stderr)
self.assertEqual(2, retcode)
self.checkBlock(stdout, expectated_stdout)
def testRevInfo(self):
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):
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):
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):
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):
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):
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):
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",',
'}',
]))
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([
'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}"],',
'}]',
]))
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([
'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([
'foo_val',
'foo_rev',
'bar_rev',
], results[0].splitlines())
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([
'foo_val',
'foo_rev',
'bar_rev',
], results[0].splitlines())
# TODO(crbug.com/1024683): Enable for windows.
@unittest.skipIf(sys.platform == 'win32', 'not yet fixed on win')
def testFlatten(self):
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
}]
self.gclient([
'sync',
'--spec=solutions=%s' % solutions
])
with open(output_deps) as f:
deps_contents = f.read()
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())
# TODO(crbug.com/1024683): Enable for windows.
@unittest.skipIf(sys.platform == 'win32', 'not yet fixed on win')
def testFlattenPinAllDeps(self):
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.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())
# TODO(crbug.com/1024683): Enable for windows.
@unittest.skipIf(sys.platform == 'win32', 'not yet fixed on win')
def testFlattenRecursedeps(self):
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.assertEqual([
'gclient_gn_args_file = "src/repo8/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)
# TODO(crbug.com/1024683): Enable for windows.
@unittest.skipIf(sys.platform == 'win32', 'not yet fixed on win')
def testFlattenCipd(self):
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.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()
if not self.enabled:
self.skipTest('git fake repos not available')
# TODO(crbug.com/1024683): Enable for windows.
@unittest.skipIf(sys.platform == 'win32', 'not yet fixed on win')
def testRevertAndStatus(self):
# 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 = ''.join([
'solutions = [{'
' "name" : "src",'
' "url" : %(git_base)r + "repo_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):
# 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 = ''.join([
'solutions = [{'
' "name" : "src",'
' "url" : %(git_base)r + "repo_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()
if not self.enabled:
self.skipTest('git fake repos not available')
def testSkiaDEPSChangeGit(self):
# Create an initial checkout:
# - Single checkout at the root.
# - Multiple checkouts in a shared subdirectory.
self.gclient(['config', '--spec',
'solutions=['
'{"name": "src",'
' "url": ' + repr(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()
if not self.enabled:
self.skipTest('git fake repos not available')
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."""
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."""
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."""
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()
if not self.enabled:
self.skipTest('git fake repos not available')
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'])
self.gclient(['sync'])
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.
self.gclient(
['sync', '-v', '-v', '-v', '--revision', self.githash('repo_13', 1)])
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.
self.gclient(
['sync', '-v', '-v', '-v', '--revision', self.githash('repo_13', 3),
'--delete_unversioned_trees'])
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.
self.gclient(
['sync', '-v', '-v', '-v', '--revision', self.githash('repo_13', 3),
'--delete_unversioned_trees'])
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.
self.gclient(
['sync', '-v', '-v', '-v', '--revision', self.githash('repo_13', 1)])
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()
#!/usr/bin/env vpython3
# Copyright (c) 2020 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 re
import sys
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
GCLIENT_PATH = os.path.join(ROOT_DIR, 'gclient')
sys.path.insert(0, ROOT_DIR)
import subprocess2
from testing_support import fake_repos
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'
# Suppress Python 3 warnings and other test undesirables.
self.env['GCLIENT_TEST'] = '1'
self.maxDiff = None
def gclient(self, cmd, cwd=None, error_ok=False):
if not cwd:
cwd = self.root_dir
cmd = [GCLIENT_PATH] + cmd
process = subprocess2.Popen(
cmd, cwd=cwd, env=self.env, stdout=subprocess2.PIPE,
stderr=subprocess2.PIPE, 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))
if not error_ok:
self.assertEqual(0, process.returncode, 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, _) = self.gclient(cmd)
if untangle:
stdout = self.untangle(stdout)
self.checkString(expected_stderr, stderr)
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
#!/usr/bin/env vpython3
# Copyright (c) 2020 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 simulate the behavior of bisect bots as they transition
across DEPS changes.
"""
import logging
import os
import sys
import unittest
import gclient_smoketest_base
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, ROOT_DIR)
import scm
from testing_support import fake_repos
class SkiaDEPSTransitionSmokeTest(gclient_smoketest_base.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()
if not self.enabled:
self.skipTest('git fake repos not available')
def testSkiaDEPSChangeGit(self):
# Create an initial checkout:
# - Single checkout at the root.
# - Multiple checkouts in a shared subdirectory.
self.gclient(['config', '--spec',
'solutions=['
'{"name": "src",'
' "url": ' + repr(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(scm.GIT.Capture(['config', 'remote.origin.url'],
skia_gyp), gyp_git_url)
self.assertEqual(scm.GIT.Capture(['config', 'remote.origin.url'],
skia_include), include_git_url)
self.assertEqual(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(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(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(scm.GIT.Capture(['config', 'remote.origin.url'],
skia_gyp), gyp_git_url)
self.assertEqual(scm.GIT.Capture(['config', 'remote.origin.url'],
skia_include), include_git_url)
self.assertEqual(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(scm.GIT.Capture(['config', 'remote.origin.url'],
skia_gyp), gyp_git_url)
self.assertEqual(scm.GIT.Capture(['config', 'remote.origin.url'],
skia_include), include_git_url)
self.assertEqual(scm.GIT.Capture(['config', 'remote.origin.url'],
skia_src), src_git_url)
class BlinkDEPSTransitionSmokeTest(gclient_smoketest_base.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()
if not self.enabled:
self.skipTest('git fake repos not available')
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(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."""
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."""
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."""
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)
if __name__ == '__main__':
if '-v' in sys.argv:
logging.basicConfig(level=logging.DEBUG)
unittest.main()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment