blob: f175b30d2b4b8b0f4b81f4bb62f6dca1dde37aa7 [file] [log] [blame]
# Copyright 2012 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 sync stages."""
import os
from unittest import mock
from chromite.cbuildbot import commands
from chromite.cbuildbot import manifest_version
from chromite.cbuildbot import repository
from chromite.cbuildbot import trybot_patch_pool
from chromite.cbuildbot.stages import generic_stages_unittest
from chromite.cbuildbot.stages import sync_stages
from chromite.lib import constants
from chromite.lib import cros_test_lib
from chromite.lib.buildstore import FakeBuildStore
pytestmark = cros_test_lib.pytestmark_inside_only
# It's normal for unittests to access protected members.
# pylint: disable=protected-access
class BootstrapStageTest(
generic_stages_unittest.AbstractStageTestCase,
cros_test_lib.RunCommandTestCase,
):
"""Tests the Bootstrap stage."""
BOT_ID = "sync-test-cbuildbot"
RELEASE_TAG = ""
def setUp(self) -> None:
# Pretend API version is always current.
self.PatchObject(
commands,
"GetTargetChromiteApiVersion",
return_value=(
constants.REEXEC_API_MAJOR,
constants.REEXEC_API_MINOR,
),
)
self._Prepare()
self.buildstore = FakeBuildStore()
def ConstructStage(self):
patch_pool = trybot_patch_pool.TrybotPatchPool()
return sync_stages.BootstrapStage(
self._run, self.buildstore, patch_pool
)
def testSimpleBootstrap(self) -> None:
"""Verify Bootstrap behavior in a simple case (with a branch)."""
self.RunStage()
# Clone next chromite checkout.
self.assertCommandContains(
[
"git",
"clone",
constants.CHROMITE_URL,
mock.ANY, # Can't predict new chromium checkout diretory.
"--reference",
mock.ANY,
]
)
# Switch to the test branch.
self.assertCommandContains(["git", "checkout", "ooga_booga"])
# Re-exec cbuildbot. We mostly only want to test the CL options
# Bootstrap changes.
# '--sourceroot=%s'
# '--test-bootstrap'
# '--nobootstrap'
# '--manifest-repo-url'
self.assertCommandContains(
[
"chromite/bin/cbuildbot",
"sync-test-cbuildbot",
"-r",
os.path.join(self.tempdir, "buildroot"),
"--buildbot",
"--noprebuilts",
"--buildnumber",
"1234321",
"--branch",
"ooga_booga",
"--sourceroot",
mock.ANY,
"--nobootstrap",
]
)
class ManifestVersionedSyncStageTest(
generic_stages_unittest.AbstractStageTestCase
):
"""Tests the ManifestVersionedSync stage."""
# pylint: disable=abstract-method
def setUp(self) -> None:
self.source_repo = "ssh://source/repo"
self.manifest_version_url = "fake manifest url"
self.branch = "master"
self.build_name = "amd64-generic"
self.incr_type = "branch"
self.next_version = "next_version"
self.sync_stage = None
self.buildstore = FakeBuildStore()
self.repo = repository.RepoRepository(
self.source_repo, self.tempdir, self.branch
)
self.manager = manifest_version.BuildSpecsManager(
self.repo,
self.manifest_version_url,
[self.build_name],
self.incr_type,
force=False,
branch=self.branch,
buildstore=self.buildstore,
dry_run=True,
)
self._Prepare()
# Our API here is not great when it comes to kwargs passing.
def _Prepare(
self, bot_id=None, **kwargs
) -> None: # pylint: disable=arguments-differ
super()._Prepare(bot_id, **kwargs)
self._run.config["manifest_version"] = self.manifest_version_url
self.sync_stage = sync_stages.ManifestVersionedSyncStage(
self._run, self.buildstore
)
self.sync_stage.manifest_manager = self.manager
self._run.attrs.manifest_manager = self.manager
def testManifestVersionedSyncOnePartBranch(self) -> None:
"""Tests basic ManifestVersionedSyncStage with branch ooga_booga"""
self.PatchObject(sync_stages.ManifestVersionedSyncStage, "Initialize")
self.PatchObject(
sync_stages.ManifestVersionedSyncStage,
"_SetAndroidVersionIfApplicable",
)
self.PatchObject(
sync_stages.ManifestVersionedSyncStage,
"_SetChromeVersionIfApplicable",
)
self.PatchObject(
manifest_version.BuildSpecsManager,
"GetNextBuildSpec",
return_value=self.next_version,
)
self.PatchObject(
manifest_version.BuildSpecsManager, "GetLatestPassingSpec"
)
self.PatchObject(
sync_stages.SyncStage,
"ManifestCheckout",
return_value=self.next_version,
)
self.PatchObject(
sync_stages.ManifestVersionedSyncStage,
"_GetMasterVersion",
return_value="foo",
autospec=True,
)
self.PatchObject(
manifest_version.BuildSpecsManager,
"BootstrapFromVersion",
autospec=True,
)
self.PatchObject(repository.RepoRepository, "Sync", autospec=True)
self.sync_stage.Run()
def testInitialize(self) -> None:
self.PatchObject(sync_stages.SyncStage, "_InitializeRepo")
self.sync_stage.repo = self.repo
self.sync_stage.Initialize()
class MockPatch(mock.MagicMock):
"""MagicMock for a GerritPatch-like object."""
gerrit_number = "1234"
patch_number = "1"
project = "chromiumos/chromite"
status = "NEW"
internal = False
current_patch_set = {
"number": patch_number,
"draft": False,
}
patch_dict = {
"currentPatchSet": current_patch_set,
}
remote = "cros"
mock_diff_status = {}
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
# Flags can vary per-patch.
self.flags = {
"CRVW": "2",
"VRIF": "1",
"COMR": "1",
"LCQ": "1",
}
def HasApproval(self, field, allowed):
"""Pretends the patch is good.
Pretend the patch has all of the values listed in
constants.DEFAULT_CQ_READY_FIELDS, but not any other fields.
Args:
field: The name of the field as a string. 'CRVW', etc.
allowed: Value, or list of values that are acceptable expressed as
strings.
"""
flag_value = self.flags.get(field, 0)
if isinstance(allowed, (tuple, list)):
return flag_value in allowed
else:
return flag_value == allowed
def IsDraft(self):
"""Whether this patch is a draft patchset."""
return self.current_patch_set["draft"]
def IsBeingMerged(self):
"""Whether this patch is merged or in the middle of being merged."""
return self.status in ("SUBMITTED", "MERGED")
def GetDiffStatus(self, _):
return self.mock_diff_status