blob: 69fa11f81e525932b2840b302724e1a0da7b99f2 [file] [log] [blame]
# Copyright 2016 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Unittests for loman.py"""
import os
from xml.etree import ElementTree
from chromite.lib import cros_test_lib
from chromite.lib import osutils
from chromite.lib import partial_mock
from chromite.scripts import loman
class RunGitMock(partial_mock.PartialCmdMock):
"""Partial mock for git.RunGit."""
TARGET = "chromite.lib.git"
ATTRS = ("RunGit",)
DEFAULT_ATTR = "RunGit"
def RunGit(self, _git_repo, cmd, _retry=True, **kwargs):
return self._results["RunGit"].LookupResult(
(cmd,), hook_args=(cmd,), hook_kwargs=kwargs
)
class ParserTest(cros_test_lib.OutputTestCase):
"""Tests for the CLI parser."""
def setUp(self) -> None:
self.parser = loman.GetParser()
def testNoCommand(self) -> None:
"""Require a command at least."""
with self.OutputCapturer():
self.assertRaises(SystemExit, self.parser.parse_args, [])
def testBadCommand(self) -> None:
"""Reject unknown commands."""
with self.OutputCapturer():
self.assertRaises(SystemExit, self.parser.parse_args, ["flyaway"])
def testAddCommand(self) -> None:
"""Verify basic add command behavior."""
with self.OutputCapturer():
self.parser.parse_args(["add", "--workon", "project"])
self.parser.parse_args(
["add", "project", "path", "--remote", "foo"]
)
class ManifestTest(cros_test_lib.TempDirTestCase):
"""Tests that need a real .repo/ manifest layout."""
def setUp(self) -> None:
# The loman code looks for the repo root, so make one, and chdir there.
os.chdir(self.tempdir)
for d in ("repo", "manifests", "manifests.git"):
osutils.SafeMakedirs(os.path.join(".repo", d))
for m in ("default.xml", "full.xml", "minilayout.xml"):
osutils.Touch(os.path.join(".repo", "manifests", m))
self._SetManifest("default.xml")
def _SetManifest(self, manifest) -> None:
"""Set active manifest to point to |manifest|."""
source = os.path.join(".repo", "manifest.xml")
target = os.path.join("manifests", manifest)
osutils.SafeUnlink(source)
os.symlink(target, source)
class AddTest(cros_test_lib.MockOutputTestCase, ManifestTest):
"""Tests for the add command."""
def testRejectBadCommands(self) -> None:
"""Reject bad invocations."""
bad_cmds = (
# Missing path.
["add"],
# Extra project.
["add", "--workon", "path", "project"],
# Missing --remote.
["add", "path", "project"],
# Missing project.
["add", "path", "--remote", "remote"],
)
with self.OutputCapturer():
for cmd in bad_cmds:
self.assertRaises(SystemExit, loman.main, cmd)
class NoMiniayoutTest(cros_test_lib.MockOutputTestCase, ManifestTest):
"""Check deprecated minilayout setups are detected."""
def setUp(self) -> None:
self._SetManifest("minilayout.xml")
def testMiniLayoutDetected(self) -> None:
"""Check error is raised when repo is setup with minilayout."""
class _Error(Exception):
"""Stub for test."""
self.PatchObject(loman, "_AssertNotMiniLayout", side_effect=_Error)
cmd = ["add", "-w", "foo"]
with self.OutputCapturer():
self.assertRaises(_Error, loman.main, cmd)
class IncludeXmlTest(cros_test_lib.MockOutputTestCase, ManifestTest):
"""End to End tests for reading and producing XML trees."""
PROJECT = "chromiumos/repohooks"
def setUp(self) -> None:
INCLUDING_XML = "including.xml"
INCLUDED_XML = "included.xml"
osutils.WriteFile(
os.path.join(".repo", "manifests", INCLUDING_XML),
"""
<manifest>
<include name="%s" />
<project remote="cros-internal" path="crostools" groups="br" name="ct" />
</manifest>"""
% (INCLUDED_XML,),
)
osutils.WriteFile(
os.path.join(".repo", "manifests", INCLUDED_XML),
"""
<manifest>
<default remote="cros" revision="HEAD" />
<remote name="cros" />
<remote name="cros-internal" />
<project path="src/repohooks" name="%s" groups="minilayout,bt" />
</manifest>"""
% (self.PROJECT,),
)
self._SetManifest(INCLUDING_XML)
self.git_mock = self.StartPatcher(RunGitMock())
self.git_mock.AddCmdResult(
["symbolic-ref", "-q", "HEAD"], stdout="default"
)
self.git_mock.AddCmdResult(
["config", "--get-regexp", "branch\\.default\\.(remote|merge)"],
stdout="branch.default.merge firmware-branch",
)
self.git_mock.AddCmdResult(
[
"config",
"-f",
os.path.join(self.tempdir, ".repo", "manifests.git", "config"),
"--get",
"manifest.groups",
],
stdout="group1,group2",
)
def testAddExistingProject(self) -> None:
"""Add an existing project, check no local_manifest.xml are created."""
self.git_mock.AddCmdResult(
[
"config",
"-f",
os.path.join(self.tempdir, ".repo", "manifests.git", "config"),
"manifest.groups",
"minilayout,platform-linux,group1,group2,name:%s"
% (self.PROJECT,),
]
)
cmd = ["add", "-w", self.PROJECT]
with self.OutputCapturer():
self.assertEqual(loman.main(cmd), 0)
self.assertNotExists(os.path.join(".repo", "local_manifest.xml"))
def testAddNewProject(self) -> None:
"""Add new project to the repo.
Check local_manifest.xml is created and valid.
"""
new_project = "project"
self.git_mock.AddCmdResult(
[
"config",
"-f",
os.path.join(self.tempdir, ".repo", "manifests.git", "config"),
"manifest.groups",
"minilayout,platform-linux,group1,group2,name:%s"
% (new_project,),
],
)
cmd = ["add", new_project, "path", "-r", "remote"]
with self.OutputCapturer():
self.assertEqual(loman.main(cmd), 0)
expected_local_manifest_nodes = ElementTree.fromstring(
"""
<manifest>
<project name="project" path="path" remote="remote" workon="False" />
</manifest>"""
)
with open(
os.path.join(".repo", "local_manifest.xml"), encoding="utf-8"
) as f:
local_manifest_nodes = ElementTree.fromstring(f.read())
# Read project, check for failure.
self.assertEqual(
ElementTree.tostring(expected_local_manifest_nodes),
ElementTree.tostring(local_manifest_nodes),
)
# Check that re-adding triggers error.
cmd = ["add", new_project, "path", "-r", "remote"]
with self.OutputCapturer() as output:
self.assertRaises(SystemExit, loman.main, cmd)
self.assertIn("conflicts with", "\n".join(output.GetStderrLines()))