blob: 9d2cdfa1e05effda2623c7ce39dcb0d11ca7f655 [file] [log] [blame]
# Copyright (c) 2012 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.
"""Unittests for lkgm_manager"""
from __future__ import print_function
import contextlib
import mock
import os
import tempfile
from xml.dom import minidom
from chromite.cbuildbot import lkgm_manager
from chromite.cbuildbot import manifest_version
from chromite.cbuildbot import repository
from chromite.cbuildbot import validation_pool
from chromite.lib import config_lib
from chromite.lib import constants
from chromite.lib import cros_build_lib
from chromite.lib import cros_logging as logging
from chromite.lib import cros_test_lib
from chromite.lib import git
from chromite.lib import osutils
from chromite.lib import patch as cros_patch
site_config = config_lib.GetConfig()
FAKE_VERSION_STRING = '1.2.4-rc3'
FAKE_VERSION_STRING_NEXT = '1.2.4-rc4'
CHROME_BRANCH = '13'
FAKE_VERSION = """
CHROMEOS_BUILD=1
CHROMEOS_BRANCH=2
CHROMEOS_PATCH=4
CHROME_BRANCH=13
"""
# pylint: disable=protected-access
class LKGMCandidateInfoTest(cros_test_lib.TestCase):
"""Test methods testing methods in _LKGMCandidateInfo class."""
def testLoadFromString(self):
"""Tests whether we can load from a string."""
info = lkgm_manager._LKGMCandidateInfo(version_string=FAKE_VERSION_STRING,
chrome_branch=CHROME_BRANCH)
self.assertEqual(info.VersionString(), FAKE_VERSION_STRING)
def testIncrementVersionPatch(self):
"""Tests whether we can increment a lkgm info."""
info = lkgm_manager._LKGMCandidateInfo(version_string=FAKE_VERSION_STRING,
chrome_branch=CHROME_BRANCH)
info.IncrementVersion()
self.assertEqual(info.VersionString(), FAKE_VERSION_STRING_NEXT)
def testVersionCompare(self):
"""Tests whether our comparision method works."""
info0 = lkgm_manager._LKGMCandidateInfo('5.2.3-rc100')
info1 = lkgm_manager._LKGMCandidateInfo('1.2.3-rc1')
info2 = lkgm_manager._LKGMCandidateInfo('1.2.3-rc2')
info3 = lkgm_manager._LKGMCandidateInfo('1.2.200-rc1')
info4 = lkgm_manager._LKGMCandidateInfo('1.4.3-rc1')
self.assertGreater(info0, info1)
self.assertGreater(info0, info2)
self.assertGreater(info0, info3)
self.assertGreater(info0, info4)
self.assertGreater(info2, info1)
self.assertGreater(info3, info1)
self.assertGreater(info3, info2)
self.assertGreater(info4, info1)
self.assertGreater(info4, info2)
self.assertGreater(info4, info3)
self.assertEqual(info0, info0)
self.assertEqual(info1, info1)
self.assertEqual(info2, info2)
self.assertEqual(info3, info3)
self.assertEqual(info4, info4)
self.assertNotEqual(info0, info1)
self.assertNotEqual(info0, info2)
self.assertNotEqual(info0, info3)
self.assertNotEqual(info0, info4)
self.assertNotEqual(info1, info0)
self.assertNotEqual(info1, info2)
self.assertNotEqual(info1, info3)
self.assertNotEqual(info1, info4)
self.assertNotEqual(info2, info0)
self.assertNotEqual(info2, info1)
self.assertNotEqual(info2, info3)
self.assertNotEqual(info2, info4)
self.assertNotEqual(info3, info0)
self.assertNotEqual(info3, info1)
self.assertNotEqual(info3, info2)
self.assertNotEqual(info3, info4)
self.assertNotEqual(info4, info0)
self.assertNotEqual(info4, info1)
self.assertNotEqual(info4, info1)
self.assertNotEqual(info4, info3)
@contextlib.contextmanager
def TemporaryManifest():
with tempfile.NamedTemporaryFile() as f:
# Create fake but empty manifest file.
new_doc = minidom.getDOMImplementation().createDocument(
None, 'manifest', None)
print(new_doc.toxml())
new_doc.writexml(f)
f.flush()
yield f
class LKGMManagerTest(cros_test_lib.MockTempDirTestCase):
"""Tests for the BuildSpecs manager."""
def setUp(self):
self.push_mock = self.PatchObject(git, 'CreatePushBranch')
self.source_repo = 'ssh://source/repo'
self.manifest_repo = 'ssh://manifest/repo'
self.version_file = 'version-file.sh'
self.branch = 'master'
self.build_name = 'x86-generic'
self.incr_type = 'branch'
# Create tmp subdirs based on the one provided TempDirMixin.
self.tmpdir = os.path.join(self.tempdir, "base")
osutils.SafeMakedirs(self.tmpdir)
self.tmpmandir = os.path.join(self.tempdir, "man")
osutils.SafeMakedirs(self.tmpmandir)
repo = repository.RepoRepository(
self.source_repo, self.tmpdir, self.branch, depth=1)
self.manager = lkgm_manager.LKGMManager(
repo, self.manifest_repo, self.build_name, constants.PFQ_TYPE, 'branch',
force=False, branch=self.branch, dry_run=True)
self.manager.manifest_dir = self.tmpmandir
self.manager.lkgm_path = os.path.join(
self.tmpmandir, constants.LKGM_MANIFEST)
self.manager.all_specs_dir = '/LKGM/path'
manifest_dir = self.manager.manifest_dir
self.manager.specs_for_builder = os.path.join(manifest_dir,
self.manager.rel_working_dir,
'build-name', '%(builder)s')
self.manager.SLEEP_TIMEOUT = 0
def _GetPathToManifest(self, info):
return os.path.join(self.manager.all_specs_dir, '%s.xml' %
info.VersionString())
def testCreateNewCandidate(self):
"""Tests that we can create a new candidate and uprev an old rc."""
# Let's stub out other LKGMManager calls cause they're already
# unit tested.
my_info = lkgm_manager._LKGMCandidateInfo('1.2.3')
most_recent_candidate = lkgm_manager._LKGMCandidateInfo('1.2.3-rc12')
self.manager.latest = most_recent_candidate.VersionString()
new_candidate = lkgm_manager._LKGMCandidateInfo('1.2.3-rc13')
new_manifest = 'some_manifest'
build_id = 59271
# Patch out our RepoRepository to make sure we don't corrupt real repo.
cros_source_mock = self.PatchObject(self.manager, 'cros_source')
cros_source_mock.branch = 'master'
cros_source_mock.directory = '/foo/repo'
self.PatchObject(lkgm_manager.LKGMManager, 'CheckoutSourceCode')
self.PatchObject(lkgm_manager.LKGMManager, 'CreateManifest',
return_value=new_manifest)
self.PatchObject(lkgm_manager.LKGMManager, 'HasCheckoutBeenBuilt',
return_value=False)
# Do manifest refresh work.
self.PatchObject(lkgm_manager.LKGMManager, 'RefreshManifestCheckout')
self.PatchObject(lkgm_manager.LKGMManager, 'GetCurrentVersionInfo',
return_value=my_info)
init_mock = self.PatchObject(lkgm_manager.LKGMManager,
'InitializeManifestVariables')
self.PatchObject(lkgm_manager.LKGMManager,
'GenerateBlameListSinceLKGM',
return_value=True)
self.PatchObject(lkgm_manager.LKGMManager,
'_AdjustRepoCheckoutToLocalManifest')
self.PatchObject(lkgm_manager.LKGMManager,
'_AddPatchesToManifest')
mock_pool = self.PatchObject(
validation_pool, 'ValidationPool',
build_root=self.manager.cros_source.directory,
has_chump_cls=False)
# For _AdjustRepoCheckoutToLocalManifest.
self.PatchObject(repository, 'CloneGitRepo')
self.PatchObject(git, 'CreateBranch')
# Publish new candidate.
publish_mock = self.PatchObject(lkgm_manager.LKGMManager, 'PublishManifest')
candidate_path = self.manager.CreateNewCandidate(
build_id=build_id, validation_pool=mock_pool)
self.assertEqual(candidate_path, self._GetPathToManifest(new_candidate))
publish_mock.assert_called_once_with(new_manifest,
new_candidate.VersionString(),
build_id=build_id)
init_mock.assert_called_once_with(my_info)
self.push_mock.assert_called_once_with(mock.ANY, mock.ANY, sync=False)
self.assertTrue(mock_pool.has_chump_cls)
def testCreateFromManifest(self):
"""Tests that we can create a new candidate from another manifest."""
# Let's stub out other LKGMManager calls cause they're already
# unit tested.
version = '2010.0.0-rc7'
my_info = lkgm_manager._LKGMCandidateInfo('2010.0.0')
new_candidate = lkgm_manager._LKGMCandidateInfo(version)
manifest = ('/tmp/manifest-versions-internal/paladin/buildspecs/'
'20/%s.xml' % version)
new_manifest = '/path/to/tmp/file.xml'
build_id = 20162
# Patch out our RepoRepository to make sure we don't corrupt real repo.
self.PatchObject(self.manager, 'cros_source')
filter_mock = self.PatchObject(manifest_version, 'FilterManifest',
return_value=new_manifest)
# Do manifest refresh work.
self.PatchObject(lkgm_manager.LKGMManager, 'GetCurrentVersionInfo',
return_value=my_info)
self.PatchObject(lkgm_manager.LKGMManager, 'RefreshManifestCheckout')
init_mock = self.PatchObject(lkgm_manager.LKGMManager,
'InitializeManifestVariables')
# Publish new candidate.
publish_mock = self.PatchObject(lkgm_manager.LKGMManager, 'PublishManifest')
candidate_path = self.manager.CreateFromManifest(manifest,
build_id=build_id)
self.assertEqual(candidate_path, self._GetPathToManifest(new_candidate))
self.assertEqual(self.manager.current_version, version)
filter_mock.assert_called_once_with(
manifest, whitelisted_remotes=site_config.params.EXTERNAL_REMOTES)
publish_mock.assert_called_once_with(new_manifest, version,
build_id=build_id)
init_mock.assert_called_once_with(my_info)
self.push_mock.assert_called_once_with(mock.ANY, mock.ANY, sync=False)
def testCreateNewCandidateReturnNoneIfNoWorkToDo(self):
"""Tests that we return nothing if there is nothing to create."""
new_manifest = 'some_manifest'
my_info = lkgm_manager._LKGMCandidateInfo('1.2.3')
# Patch out our RepoRepository to make sure we don't corrupt real repo.
cros_source_mock = self.PatchObject(self.manager, 'cros_source')
cros_source_mock.branch = 'master'
cros_source_mock.directory = '/foo/repo'
self.PatchObject(lkgm_manager.LKGMManager, 'CheckoutSourceCode')
self.PatchObject(lkgm_manager.LKGMManager, 'CreateManifest',
return_value=new_manifest)
self.PatchObject(lkgm_manager.LKGMManager, 'RefreshManifestCheckout')
self.PatchObject(lkgm_manager.LKGMManager, 'GetCurrentVersionInfo',
return_value=my_info)
init_mock = self.PatchObject(lkgm_manager.LKGMManager,
'InitializeManifestVariables')
self.PatchObject(lkgm_manager.LKGMManager, 'HasCheckoutBeenBuilt',
return_value=True)
# For _AdjustRepoCheckoutToLocalManifest.
self.PatchObject(repository, 'CloneGitRepo')
self.PatchObject(git, 'CreateBranch')
candidate = self.manager.CreateNewCandidate()
self.assertEqual(candidate, None)
init_mock.assert_called_once_with(my_info)
def _CreateManifest(self):
"""Returns a created test manifest in tmpdir with its dir_pfx."""
self.manager.current_version = '1.2.4-rc21'
dir_pfx = CHROME_BRANCH
manifest = os.path.join(self.manager.manifest_dir,
self.manager.rel_working_dir, 'buildspecs',
dir_pfx, '1.2.4-rc21.xml')
osutils.Touch(manifest)
return manifest, dir_pfx
def _MockParseGitLog(self, fake_git_log, project):
exists_mock = self.PatchObject(os.path, 'exists', return_value=True)
link_mock = self.PatchObject(logging, 'PrintBuildbotLink')
fake_project_handler = mock.Mock(spec=git.Manifest)
fake_project_handler.checkouts_by_path = {project['path']: project}
self.PatchObject(git, 'Manifest', return_value=fake_project_handler)
fake_result = cros_build_lib.CommandResult(output=fake_git_log)
self.PatchObject(git, 'RunGit', return_value=fake_result)
return exists_mock, link_mock
def testGenerateBlameListSinceLKGM(self):
"""Tests that we can generate a blamelist from two commit messages.
This test tests the functionality of generating a blamelist for a git log.
Note in this test there are two commit messages, one commited by the
Commit Queue and another from Non-Commit Queue. We test the correct
handling in both cases.
"""
fake_git_log = """Author: Sammy Sosa <fake@fake.com>
Commit: Chris Sosa <sosa@chromium.org>
Date: Mon Aug 8 14:52:06 2011 -0700
Add in a test for cbuildbot
TEST=So much testing
BUG=chromium-os:99999
Change-Id: Ib72a742fd2cee3c4a5223b8easwasdgsdgfasdf
Reviewed-on: https://chromium-review.googlesource.com/1234
Reviewed-by: Fake person <fake@fake.org>
Tested-by: Sammy Sosa <fake@fake.com>
Author: Sammy Sosa <fake@fake.com>
Commit: Gerrit <chrome-bot@chromium.org>
Date: Mon Aug 8 14:52:06 2011 -0700
Add in a test for cbuildbot
TEST=So much testing
BUG=chromium-os:99999
Change-Id: Ib72a742fd2cee3c4a5223b8easwasdgsdgfasdf
Reviewed-on: https://chromium-review.googlesource.com/1235
Reviewed-by: Fake person <fake@fake.org>
Tested-by: Sammy Sosa <fake@fake.com>
"""
project = {
'name': 'fake/repo',
'path': 'fake/path',
'revision': '1234567890',
}
self.manager.incr_type = 'build'
self.PatchObject(cros_build_lib, 'RunCommand', side_effect=Exception())
exists_mock, link_mock = self._MockParseGitLog(fake_git_log, project)
self.manager.GenerateBlameListSinceLKGM()
exists_mock.assert_called_once_with(
os.path.join(self.tmpdir, project['path']))
link_mock.assert_has_calls([
mock.call('CHUMP | repo | fake | 1234',
'https://chromium-review.googlesource.com/1234'),
mock.call('repo | fake | 1235',
'https://chromium-review.googlesource.com/1235'),
])
def testGenerateBlameListHasChumpCL(self):
"""Test GenerateBlameList with chump CLs."""
fake_git_log = """
Author: Sammy Sosa <fake@fake.com>
Commit: Chris Sosa <sosa@chromium.org>
Date: Mon Aug 8 14:52:06 2011 -0700
Add in a test for cbuildbot
TEST=So much testing
BUG=chromium-os:99999
Change-Id: Ib72a742fd2cee3c4a5223b8easwasdgsdgfasdf
Reviewed-on: https://chromium-review.googlesource.com/1234
Reviewed-by: Fake person <fake@fake.org>
Tested-by: Sammy Sosa <fake@fake.com>
Author: Sammy Sosa <fake@fake.com>
Commit: Gerrit <chrome-bot@chromium.org>
"""
project = {
'name': 'fake/repo',
'path': 'fake/path',
'revision': '1234567890',
}
_, link_mock = self._MockParseGitLog(fake_git_log, project)
has_chump_cls = lkgm_manager.GenerateBlameList(
self.manager.cros_source, self.manager.lkgm_path)
self.assertTrue(has_chump_cls)
link_mock.assert_has_calls([
mock.call('CHUMP | repo | fake | 1234',
'https://chromium-review.googlesource.com/1234')])
def testGenerateBlameListNoChumpCL(self):
"""Test GenerateBlameList without chump CLs."""
fake_git_log = """Author: Sammy Sosa <fake@fake.com>
Commit: Gerrit <chrome-bot@chromium.org>
Date: Mon Aug 8 14:52:06 2011 -0700
Add in a test for cbuildbot
TEST=So much testing
BUG=chromium-os:99999
Change-Id: Ib72a742fd2cee3c4a5223b8easwasdgsdgfasdf
Reviewed-on: https://chromium-review.googlesource.com/1235
Reviewed-by: Fake person <fake@fake.org>
Tested-by: Sammy Sosa <fake@fake.com>
"""
project = {
'name': 'fake/repo',
'path': 'fake/path',
'revision': '1234567890',
}
_, link_mock = self._MockParseGitLog(fake_git_log, project)
has_chump_cl = lkgm_manager.GenerateBlameList(
self.manager.cros_source, self.manager.lkgm_path)
self.assertFalse(has_chump_cl)
link_mock.assert_has_calls([
mock.call('repo | fake | 1235',
'https://chromium-review.googlesource.com/1235')])
def testAddChromeVersionToManifest(self):
"""Tests whether we can write the chrome version to the manifest file."""
with TemporaryManifest() as f:
chrome_version = '35.0.1863.0'
# Write the chrome element to manifest.
self.manager._AddChromeVersionToManifest(f.name, chrome_version)
# Read the manifest file.
new_doc = minidom.parse(f.name)
elements = new_doc.getElementsByTagName(lkgm_manager.CHROME_ELEMENT)
self.assertEqual(len(elements), 1)
self.assertEqual(
elements[0].getAttribute(lkgm_manager.CHROME_VERSION_ATTR),
chrome_version)
def testAddLKGMToManifest(self, present=True):
"""Tests whether we can write the LKGM version to the manifest file."""
with TemporaryManifest() as f:
# Set up LGKM symlink.
if present:
lkgm_version = '6377.0.0-rc1'
os.makedirs(os.path.dirname(self.manager.lkgm_path))
os.symlink('../foo/%s.xml' % lkgm_version, self.manager.lkgm_path)
# Write the chrome element to manifest.
self.manager._AddLKGMToManifest(f.name)
# Read the manifest file.
new_doc = minidom.parse(f.name)
elements = new_doc.getElementsByTagName(lkgm_manager.LKGM_ELEMENT)
if present:
self.assertEqual(len(elements), 1)
self.assertEqual(
elements[0].getAttribute(lkgm_manager.LKGM_VERSION_ATTR),
lkgm_version)
else:
self.assertEqual(len(elements), 0)
def testAddLKGMToManifestWithMissingFile(self):
"""Tests writing the LKGM version when LKGM.xml is missing."""
self.testAddLKGMToManifest(present=False)
def _MockValidationPool(self, gerrit_patchs):
mock_pool = mock.Mock()
mock_pool.applied = gerrit_patchs
return mock_pool
def testAddPatchesToManifest(self):
"""Tests whether we can add a fake patch to an empty manifest file.
This test creates an empty xml file with just manifest/ tag in it then
runs the AddPatchesToManifest with one mocked out GerritPatch and ensures
the newly generated manifest has the correct patch information afterwards.
"""
with TemporaryManifest() as f:
gerrit_patch = cros_patch.GerritFetchOnlyPatch(
'https://host/chromite/tacos',
'chromite/tacos',
'refs/changes/11/12345/4',
'master',
'cros-internal',
'7181e4b5e182b6f7d68461b04253de095bad74f9',
'I47ea30385af60ae4cc2acc5d1a283a46423bc6e1',
'12345',
'4',
'foo@chromium.org',
1,
1,
3)
mock_pool = self._MockValidationPool([gerrit_patch])
self.manager._AddPatchesToManifest(f.name, mock_pool)
new_doc = minidom.parse(f.name)
element = new_doc.getElementsByTagName(
lkgm_manager.PALADIN_COMMIT_ELEMENT)[0]
self.assertEqual(element.getAttribute(
cros_patch.ATTR_CHANGE_ID), gerrit_patch.change_id)
self.assertEqual(element.getAttribute(
cros_patch.ATTR_COMMIT), gerrit_patch.commit)
self.assertEqual(element.getAttribute(cros_patch.ATTR_PROJECT),
gerrit_patch.project)
self.assertEqual(element.getAttribute(cros_patch.ATTR_REMOTE),
gerrit_patch.remote)
self.assertEqual(element.getAttribute(cros_patch.ATTR_BRANCH),
gerrit_patch.tracking_branch)
self.assertEqual(element.getAttribute(cros_patch.ATTR_REF),
gerrit_patch.ref)
self.assertEqual(
element.getAttribute(cros_patch.ATTR_OWNER_EMAIL),
gerrit_patch.owner_email)
self.assertEqual(
element.getAttribute(cros_patch.ATTR_PROJECT_URL),
gerrit_patch.project_url)
self.assertEqual(
element.getAttribute(cros_patch.ATTR_PATCH_NUMBER),
gerrit_patch.patch_number)
self.assertEqual(
element.getAttribute(cros_patch.ATTR_FAIL_COUNT),
str(gerrit_patch.fail_count))
self.assertEqual(
element.getAttribute(cros_patch.ATTR_PASS_COUNT),
str(gerrit_patch.pass_count))
self.assertEqual(
element.getAttribute(cros_patch.ATTR_TOTAL_FAIL_COUNT),
str(gerrit_patch.total_fail_count))
def testAddPatchesToManifestWithUnicode(self):
"""Tests to add a fake patch with unicode to an empty manifest file.
Test whether _AddPatchesToManifest can add to a patch with unicode to
manifest file without any UnicodeError exception and that the decoded
manifest has the original unicode string.
"""
with TemporaryManifest() as f:
gerrit_patch = cros_patch.GerritFetchOnlyPatch(
'https://host/chromite/tacos',
'chromite/tacos',
'refs/changes/11/12345/4',
'master',
'cros-internal',
'7181e4b5e182b6f7d68461b04253de095bad74f9',
'I47ea30385af60ae4cc2acc5d1a283a46423bc6e1',
'12345',
'4',
u'foo\xe9@chromium.org',
1,
1,
3)
mock_pool = self._MockValidationPool([gerrit_patch])
self.manager._AddPatchesToManifest(f.name, mock_pool)
new_doc = minidom.parse(f.name)
element = new_doc.getElementsByTagName(
lkgm_manager.PALADIN_COMMIT_ELEMENT)[0]
self.assertEqual(
element.getAttribute(cros_patch.ATTR_OWNER_EMAIL),
gerrit_patch.owner_email)
def testAddPatchesToManifestWithInvalidTokens(self):
"""Tests to add a fake patch with invalid tokens to a manifest.
Test whether _AddPatchesToManifest will skip commits with invalid tokens.
"""
with TemporaryManifest() as f:
gerrit_patch = cros_patch.GerritFetchOnlyPatch(
'https://host/chromite/tacos',
'chromite/tacos',
'refs/changes/11/12345/4',
'master',
'cros-internal',
'7181e4b5e182b6f7d68461b04253de095bad74f9',
'I47ea30385af60ae4cc2acc5d1a283a46423bc6e1',
'12345',
'4',
'foo@chromium.org',
1,
1,
3,
#Invalid tokens
'…')
mock_pool = self._MockValidationPool([gerrit_patch])
self.manager._AddPatchesToManifest(f.name, mock_pool)
new_doc = minidom.parse(f.name)
self.assertEqual(0, len(new_doc.getElementsByTagName(
lkgm_manager.PALADIN_COMMIT_ELEMENT)))
self.assertEqual(1, mock_pool.SendNotification.call_count)
self.assertEqual(1, mock_pool.RemoveReady.call_count)