blob: 446a9b025bf51dea0c3dadb5d62cae8c9be83642 [file] [log] [blame]
# Copyright 2015 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Test the path_util module."""
from __future__ import print_function
import itertools
import mock
import os
import tempfile
from chromite.cbuildbot import constants
from chromite.lib import bootstrap_lib
from chromite.lib import cros_build_lib_unittest
from chromite.lib import cros_test_lib
from chromite.lib import git
from chromite.lib import partial_mock
from chromite.lib import path_util
from chromite.lib import workspace_lib
FAKE_SOURCE_PATH = '/path/to/source/tree'
FAKE_REPO_PATH = '/path/to/repo'
FAKE_WORKSPACE_NESTED_CHROOT_DIR = '.fake_chroot'
FAKE_WORKSPACE_STANDALONE_CHROOT_PATH = '/path/to/chroot'
CUSTOM_SOURCE_PATH = '/custom/source/path'
class DetermineCheckoutTest(cros_test_lib.MockTempDirTestCase):
"""Verify functionality for figuring out what checkout we're in."""
def setUp(self):
self.rc_mock = cros_build_lib_unittest.RunCommandMock()
self.StartPatcher(self.rc_mock)
self.rc_mock.SetDefaultCmdResult()
def RunTest(self, dir_struct, cwd, expected_root, expected_type,
expected_src):
"""Run a test with specific parameters and expected results."""
cros_test_lib.CreateOnDiskHierarchy(self.tempdir, dir_struct)
cwd = os.path.join(self.tempdir, cwd)
checkout_info = path_util.DetermineCheckout(cwd)
full_root = expected_root
if expected_root is not None:
full_root = os.path.join(self.tempdir, expected_root)
full_src = expected_src
if expected_src is not None:
full_src = os.path.join(self.tempdir, expected_src)
self.assertEquals(checkout_info.root, full_root)
self.assertEquals(checkout_info.type, expected_type)
self.assertEquals(checkout_info.chrome_src_dir, full_src)
def testGclientRepo(self):
"""Recognizes a GClient repo checkout."""
dir_struct = [
'a/.gclient',
'a/b/.repo/',
'a/b/c/.gclient',
'a/b/c/d/somefile',
]
self.RunTest(dir_struct, 'a/b/c', 'a/b/c',
path_util.CHECKOUT_TYPE_GCLIENT,
'a/b/c/src')
self.RunTest(dir_struct, 'a/b/c/d', 'a/b/c',
path_util.CHECKOUT_TYPE_GCLIENT,
'a/b/c/src')
self.RunTest(dir_struct, 'a/b', 'a/b',
path_util.CHECKOUT_TYPE_REPO,
None)
self.RunTest(dir_struct, 'a', 'a',
path_util.CHECKOUT_TYPE_GCLIENT,
'a/src')
def testGitUnderGclient(self):
"""Recognizes a chrome git checkout by gclient."""
self.rc_mock.AddCmdResult(
partial_mock.In('config'), output=constants.CHROMIUM_GOB_URL)
dir_struct = [
'a/.gclient',
'a/src/.git/',
]
self.RunTest(dir_struct, 'a/src', 'a',
path_util.CHECKOUT_TYPE_GCLIENT,
'a/src')
def testGitUnderRepo(self):
"""Recognizes a chrome git checkout by repo."""
self.rc_mock.AddCmdResult(
partial_mock.In('config'), output=constants.CHROMIUM_GOB_URL)
dir_struct = [
'a/.repo/',
'a/b/.git/',
]
self.RunTest(dir_struct, 'a/b', 'a',
path_util.CHECKOUT_TYPE_REPO,
None)
def testBadGit1(self):
""".git is not a directory."""
self.RunTest(['a/.git'], 'a', None,
path_util.CHECKOUT_TYPE_UNKNOWN, None)
def testBadGit2(self):
"""'git config' returns nothing."""
self.RunTest(['a/.repo/', 'a/b/.git/'], 'a/b', 'a',
path_util.CHECKOUT_TYPE_REPO, None)
def testBadGit3(self):
"""'git config' returns error."""
self.rc_mock.AddCmdResult(partial_mock.In('config'), returncode=5)
self.RunTest(['a/.git/'], 'a', None,
path_util.CHECKOUT_TYPE_UNKNOWN, None)
def testSdkBootstrap(self):
"""Recognizes an SDK bootstrap case."""
self.rc_mock.AddCmdResult(
partial_mock.In('config'), output=constants.CHROMITE_URL)
dir_struct = [
'a/.git/',
'a/sdk_checkouts/1.0.0/.repo',
'a/sdk_checkouts/1.0.0/chromite/.git',
]
self.RunTest(dir_struct, 'a', 'a',
path_util.CHECKOUT_TYPE_SDK_BOOTSTRAP, None)
self.RunTest(dir_struct, 'a/b', 'a',
path_util.CHECKOUT_TYPE_SDK_BOOTSTRAP, None)
self.RunTest(dir_struct, 'a/sdk_checkouts', 'a',
path_util.CHECKOUT_TYPE_SDK_BOOTSTRAP, None)
self.RunTest(dir_struct, 'a/sdk_checkouts/1.0.0', 'a',
path_util.CHECKOUT_TYPE_SDK_BOOTSTRAP, None)
self.RunTest(dir_struct, 'a/sdk_checkouts/1.0.0/chromite', 'a',
path_util.CHECKOUT_TYPE_SDK_BOOTSTRAP, None)
class FindCacheDirTest(cros_test_lib.WorkspaceTestCase):
"""Test cache dir specification and finding functionality."""
def setUp(self):
dir_struct = [
'repo/.repo/',
'repo/manifest/',
'gclient/.gclient',
]
cros_test_lib.CreateOnDiskHierarchy(self.tempdir, dir_struct)
self.repo_root = os.path.join(self.tempdir, 'repo')
self.gclient_root = os.path.join(self.tempdir, 'gclient')
self.nocheckout_root = os.path.join(self.tempdir, 'nothing')
self.CreateBootstrap('1.0.0')
self.CreateWorkspace()
self.bootstrap_cache = os.path.join(
self.bootstrap_path, bootstrap_lib.SDK_CHECKOUTS,
path_util.GENERAL_CACHE_DIR)
self.rc_mock = self.StartPatcher(cros_build_lib_unittest.RunCommandMock())
self.cwd_mock = self.PatchObject(os, 'getcwd')
def testRepoRoot(self):
"""Test when we are inside a repo checkout."""
self.cwd_mock.return_value = self.repo_root
self.assertEquals(
path_util.FindCacheDir(),
os.path.join(self.repo_root, path_util.GENERAL_CACHE_DIR))
def testGclientRoot(self):
"""Test when we are inside a gclient checkout."""
self.cwd_mock.return_value = self.gclient_root
self.assertEquals(
path_util.FindCacheDir(),
os.path.join(self.gclient_root, path_util.CHROME_CACHE_DIR))
def testTempdir(self):
"""Test when we are not in any checkout."""
self.cwd_mock.return_value = self.nocheckout_root
self.assertStartsWith(
path_util.FindCacheDir(),
os.path.join(tempfile.gettempdir(), ''))
def testBootstrap(self):
"""Test when running from bootstrap."""
self.cwd_mock.return_value = self.bootstrap_path
self.rc_mock.AddCmdResult(
partial_mock.In('config'), output=constants.CHROMITE_URL)
self.assertEquals(
path_util.FindCacheDir(),
self.bootstrap_cache)
def testSdkCheckoutsInsideBootstrap(self):
"""Test when in the bootstrap SDK checkout location."""
self.cwd_mock.return_value = os.path.join(
self.bootstrap_path, bootstrap_lib.SDK_CHECKOUTS)
self.rc_mock.AddCmdResult(
partial_mock.In('config'), output=constants.CHROMITE_URL)
self.assertEquals(
path_util.FindCacheDir(),
self.bootstrap_cache)
def testSdkInsideBootstrap(self):
"""Test when in an SDK checkout inside the bootstrap."""
self.cwd_mock.return_value = os.path.join(
self.bootstrap_path, bootstrap_lib.SDK_CHECKOUTS, '1.0.0', 'chromite')
self.rc_mock.AddCmdResult(
partial_mock.In('config'), output=constants.CHROMITE_URL)
self.assertEquals(
path_util.FindCacheDir(),
self.bootstrap_cache)
def testWorkspaceWithBootstrap(self):
"""In a workspace, with boostrap path."""
self.cwd_mock.return_value = self.workspace_path
self.assertEquals(
path_util.FindCacheDir(),
self.bootstrap_cache)
def testWorkspaceWithoutBootstrap(self):
"""In a workspace, no bootstrap path."""
self.cwd_mock.return_value = self.workspace_path
self.mock_bootstrap_path.return_value = None
self.assertStartsWith(
path_util.FindCacheDir(),
os.path.join(tempfile.gettempdir(), ''))
class TestPathResolver(cros_test_lib.MockTestCase):
"""Tests of ChrootPathResolver class."""
def setUp(self):
self.PatchObject(constants, 'SOURCE_ROOT', new=FAKE_SOURCE_PATH)
self.PatchObject(path_util, 'GetCacheDir', return_value='/path/to/cache')
self.PatchObject(git, 'FindRepoDir',
return_value=os.path.join(FAKE_REPO_PATH, '.fake_repo'))
self.chroot_path = None
def FakeCwd(self, base_path):
return os.path.join(base_path, 'somewhere/in/there')
def SetChrootPath(self, workspace_path, source_path, standalone_chroot):
"""Set and fake the chroot path."""
if workspace_path is None:
self.chroot_path = os.path.join(source_path,
constants.DEFAULT_CHROOT_DIR)
else:
if standalone_chroot:
self.chroot_path = FAKE_WORKSPACE_STANDALONE_CHROOT_PATH
else:
self.chroot_path = os.path.join(workspace_path,
FAKE_WORKSPACE_NESTED_CHROOT_DIR)
self.PatchObject(workspace_lib, 'ChrootPath',
return_value=self.chroot_path)
def RunInsideChrootTests(self, workspace_path, standalone_chroot=False):
"""Tests {To,From}Chroot() calls from inside the chroot."""
self.SetChrootPath(workspace_path, constants.SOURCE_ROOT,
standalone_chroot)
resolver = path_util.ChrootPathResolver(workspace_path=workspace_path)
# Paths remain the same, only expanded/canonicalized (both directions).
self.assertEqual(os.path.realpath('some/path'),
resolver.ToChroot('some/path'))
self.assertEqual(os.path.realpath('/some/path'),
resolver.ToChroot('/some/path'))
self.assertEqual(os.path.realpath('some/path'),
resolver.FromChroot('some/path'))
self.assertEqual(os.path.realpath('/some/path'),
resolver.FromChroot('/some/path'))
@mock.patch('chromite.lib.cros_build_lib.IsInsideChroot', return_value=True)
def testInsideChrootNoWorkspace(self, _):
"""Test conversion to chroot: inside, no workspace."""
self.RunInsideChrootTests(None)
@mock.patch('chromite.lib.cros_build_lib.IsInsideChroot', return_value=True)
def testInsideChrootWithWorkspaceNestedChroot(self, _):
"""Test conversion to chroot: inside, workspace, nested chroot."""
self.RunInsideChrootTests('path/to/workspace')
@mock.patch('chromite.lib.cros_build_lib.IsInsideChroot', return_value=True)
def testInsideChrootWithWorkspaceStandaloneChroot(self, _):
"""Test convertion to chroot: inside, workspace, standalone chroot."""
self.RunInsideChrootTests('path/to/workspace', True)
def RunOutsideToChrootTests(self, workspace_path, standalone_chroot):
"""Tests ToChroot() calls from outside the chroot."""
for source_path, source_from_path_repo in itertools.product(
(None, CUSTOM_SOURCE_PATH), (False, True)):
if source_from_path_repo:
actual_source_path = FAKE_REPO_PATH
else:
actual_source_path = source_path or constants.SOURCE_ROOT
fake_cwd = self.FakeCwd(actual_source_path)
self.PatchObject(os, 'getcwd', return_value=fake_cwd)
self.SetChrootPath(workspace_path, actual_source_path, standalone_chroot)
resolver = path_util.ChrootPathResolver(
workspace_path=workspace_path,
source_path=source_path,
source_from_path_repo=source_from_path_repo)
source_rel_cwd = os.path.relpath(fake_cwd, actual_source_path)
# Case: path inside the chroot space.
self.assertEqual(
'/some/path',
resolver.ToChroot(os.path.join(self.chroot_path, 'some/path')))
# Case: path inside the workspace.
if workspace_path is not None:
self.assertEqual(
os.path.join(constants.CHROOT_WORKSPACE_ROOT, 'some/path'),
resolver.ToChroot(os.path.join(workspace_path, 'some/path')))
# Case: path inside the cache directory.
self.assertEqual(
os.path.join(constants.CHROOT_CACHE_ROOT, 'some/path'),
resolver.ToChroot(os.path.join(path_util.GetCacheDir(),
'some/path')))
# Case: absolute path inside the source tree.
if source_from_path_repo:
self.assertEqual(
os.path.join(constants.CHROOT_SOURCE_ROOT, 'some/path'),
resolver.ToChroot(os.path.join(FAKE_REPO_PATH, 'some/path')))
else:
self.assertEqual(
os.path.join(constants.CHROOT_SOURCE_ROOT, 'some/path'),
resolver.ToChroot(os.path.join(actual_source_path, 'some/path')))
# Case: relative path inside the source tree.
if source_from_path_repo:
self.assertEqual(
os.path.join(constants.CHROOT_SOURCE_ROOT, source_rel_cwd,
'some/path'),
resolver.ToChroot('some/path'))
else:
self.assertEqual(
os.path.join(constants.CHROOT_SOURCE_ROOT, source_rel_cwd,
'some/path'),
resolver.ToChroot('some/path'))
# Case: unreachable, path with improper source root prefix.
with self.assertRaises(ValueError):
resolver.ToChroot(os.path.join(actual_source_path + '-foo',
'some/path'))
# Case: unreachable (random).
with self.assertRaises(ValueError):
resolver.ToChroot('/some/path')
@mock.patch('chromite.lib.cros_build_lib.IsInsideChroot', return_value=False)
def testOutsideToChrootNoWorkspace(self, _):
"""Test inbound translation w/o workspace."""
self.RunOutsideToChrootTests(None, False)
@mock.patch('chromite.lib.cros_build_lib.IsInsideChroot', return_value=False)
def testOutsideToChrootStandaloneWorkspaceNestedChroot(self, _):
"""Test inbound translation w/ standalone workspace + nested chroot."""
self.RunOutsideToChrootTests('/path/to/workspace', False)
@mock.patch('chromite.lib.cros_build_lib.IsInsideChroot', return_value=False)
def testOutsideToChrootStandaloneWorkspaceStandaloneChroot(self, _):
"""Test inbound translation w/ standalone workspace + standalone chroot."""
self.RunOutsideToChrootTests('/path/to/workspace', True)
@mock.patch('chromite.lib.cros_build_lib.IsInsideChroot', return_value=False)
def testOutsideToChrootStandaloneRelativeWorkspaceNestedChroot(self, _):
"""Test inbound w/ standalone realtive workspace + nested chroot."""
self.RunOutsideToChrootTests(
os.path.join(constants.SOURCE_ROOT, '../path/to/workspace'),
False)
@mock.patch('chromite.lib.cros_build_lib.IsInsideChroot', return_value=False)
def testOutsideToChrootStandaloneRelativeWorkspaceStandaloneChroot(self, _):
"""Test inbound w/ standalone realtive workspace + standalone chroot."""
self.RunOutsideToChrootTests(
os.path.join(constants.SOURCE_ROOT, '../path/to/workspace'),
True)
@mock.patch('chromite.lib.cros_build_lib.IsInsideChroot', return_value=False)
def testOutsideToChrootNestedWorkspaceNestedChroot(self, _):
"""Test inbound translation w/ nested workspace + nested chroot."""
self.RunOutsideToChrootTests(
os.path.join(constants.SOURCE_ROOT, 'path/to/workspace'),
False)
@mock.patch('chromite.lib.cros_build_lib.IsInsideChroot', return_value=False)
def testOutsideToChrootNestedWorkspaceStandaloneChroot(self, _):
"""Test inbound translation w/ nested workspace + standalone chroot."""
self.RunOutsideToChrootTests(
os.path.join(constants.SOURCE_ROOT, 'path/to/workspace'),
True)
@mock.patch('chromite.lib.cros_build_lib.IsInsideChroot', return_value=False)
def testOutsideToChrootNestedRelativeWorkspaceNestedChroot(self, _):
"""Test inbound translation w/ nested realtive workspace + nested chroot."""
self.RunOutsideToChrootTests('path/to/workspace', False)
@mock.patch('chromite.lib.cros_build_lib.IsInsideChroot', return_value=False)
def testOutsideToChrootNestedRelativeWorkspaceStandaloneChroot(self, _):
"""Test inbound w/ nested realtive workspace + standalone chroot."""
self.RunOutsideToChrootTests('path/to/workspace', True)
def RunOutsideFromChrootTests(self, workspace_path, standalone_chroot):
"""Tests FromChroot() calls from outside the chroot."""
self.PatchObject(os, 'getcwd', return_value=self.FakeCwd(FAKE_SOURCE_PATH))
self.SetChrootPath(workspace_path, constants.SOURCE_ROOT, standalone_chroot)
resolver = path_util.ChrootPathResolver(workspace_path=workspace_path)
# Case: source root path.
self.assertEqual(
os.path.join(constants.SOURCE_ROOT, 'some/path'),
resolver.FromChroot(os.path.join(constants.CHROOT_SOURCE_ROOT,
'some/path')))
if workspace_path is None:
# Case: no workspace path, workspace root resolution fails.
with self.assertRaises(ValueError):
resolver.FromChroot(os.path.join(constants.CHROOT_WORKSPACE_ROOT,
'some/path'))
# Case: cyclic source/chroot sub-path elimination.
self.assertEqual(
os.path.join(constants.SOURCE_ROOT, 'some/path'),
resolver.FromChroot(os.path.join(
constants.CHROOT_SOURCE_ROOT,
constants.DEFAULT_CHROOT_DIR,
constants.CHROOT_SOURCE_ROOT.lstrip(os.path.sep),
constants.DEFAULT_CHROOT_DIR,
constants.CHROOT_SOURCE_ROOT.lstrip(os.path.sep),
'some/path')))
else:
# Case: workspace root path.
self.assertEqual(
os.path.join(workspace_path, 'some/path'),
resolver.FromChroot(os.path.join(constants.CHROOT_WORKSPACE_ROOT,
'some/path')))
if not standalone_chroot:
# Case: cyclic workspace/chroot sub-path elimination.
self.assertEqual(
os.path.join(workspace_path, 'some/path'),
resolver.FromChroot(os.path.join(
constants.CHROOT_WORKSPACE_ROOT,
FAKE_WORKSPACE_NESTED_CHROOT_DIR,
constants.CHROOT_WORKSPACE_ROOT.lstrip(os.path.sep),
FAKE_WORKSPACE_NESTED_CHROOT_DIR,
constants.CHROOT_WORKSPACE_ROOT.lstrip(os.path.sep),
'some/path')))
# Case: path inside the cache directory.
self.assertEqual(
os.path.join(path_util.GetCacheDir(), 'some/path'),
resolver.FromChroot(os.path.join(constants.CHROOT_CACHE_ROOT,
'some/path')))
# Case: non-rooted chroot paths.
self.assertEqual(
os.path.join(self.chroot_path, 'some/path'),
resolver.FromChroot('/some/path'))
@mock.patch('chromite.lib.cros_build_lib.IsInsideChroot', return_value=False)
def testOutsideFromChrootNoWorkspace(self, _):
"""Test inbound translation w/o workspace."""
self.RunOutsideFromChrootTests(None, False)
@mock.patch('chromite.lib.cros_build_lib.IsInsideChroot', return_value=False)
def testOutsideFromChrootStandaloneWorkspaceNestedChroot(self, _):
"""Test inbound translation w/ standalone workspace + nested chroot."""
self.RunOutsideFromChrootTests('/path/to/workspace', False)
@mock.patch('chromite.lib.cros_build_lib.IsInsideChroot', return_value=False)
def testOutsideFromChrootStandaloneWorkspaceStandaloneChroot(self, _):
"""Test inbound translation w/ standalone workspace + standalone chroot."""
self.RunOutsideFromChrootTests('/path/to/workspace', True)
@mock.patch('chromite.lib.cros_build_lib.IsInsideChroot', return_value=False)
def testOutsideFromChrootNestedWorkspaceNestedChroot(self, _):
"""Test inbound translation w/ nested workspace + nested chroot."""
self.RunOutsideFromChrootTests(
os.path.join(constants.SOURCE_ROOT, 'path/to/workspace'),
False)
@mock.patch('chromite.lib.cros_build_lib.IsInsideChroot', return_value=False)
def testOutsideFromChrootNestedWorkspaceStandaloneChroot(self, _):
"""Test inbound translation w/ nested workspace + standalone chroot."""
self.RunOutsideFromChrootTests(
os.path.join(constants.SOURCE_ROOT, 'path/to/workspace'),
True)