blob: f2ff3f0930d10c18d4f3eb4d02e67d82ad8a06bd [file] [log] [blame]
# -*- coding: utf-8 -*-
# Copyright 2016 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.
"""Module that contains unittests for patch_series module."""
from __future__ import print_function
import contextlib
import os
import sys
import mock
from chromite.cbuildbot import patch_series
from chromite.lib import config_lib
from chromite.lib import gerrit
from chromite.lib import cros_test_lib
from chromite.lib import parallel_unittest
from chromite.lib import partial_mock
from chromite.lib import patch as cros_patch
from chromite.lib import patch_unittest
assert sys.version_info >= (3, 6), 'This module requires Python 3.6+'
class MockManifest(object):
"""Helper class for Mocking Manifest objects."""
def __init__(self, path, **kwargs):
self.root = path
for key, attr in kwargs.items():
setattr(self, key, attr)
def FakeFetchChangesForRepo(fetched_changes, by_repo, repo):
"""Fake version of the "PatchSeries._FetchChangesForRepo" method.
Thes does nothing to the changes and simply copies them into the output
for c in by_repo[repo]:
fetched_changes[] = c
class FakePatch(partial_mock.PartialMock):
"""Mocks out dependency and fetch methods of GitRepoPatch.
set FakePatch.parents and .build_roots per patch, and set
FakePatch.assertEqual to your TestCase's assertEqual method. The behavior
of GerritDependencies, and Fetch` depends on the patch id.
TARGET = 'chromite.lib.patch.GitRepoPatch'
ATTRS = ('GerritDependencies', 'Fetch')
parents = {}
build_root = None
assertEqual = None
def PreStart(self):
FakePatch.parents = {}
def PreStop(self):
FakePatch.build_root = None
FakePatch.assertEqual = None
def GerritDependencies(self, patch):
return [cros_patch.ParsePatchDep(x) for x in self.parents[]]
def Fetch(self, patch, path):
self._assertPath(patch, path)
return patch.sha1
def _assertPath(self, patch, path):
# pylint: disable=not-callable
os.path.join(self.build_root, patch.project))
class FakeGerritPatch(FakePatch):
"""Mocks out the "GerritDependencies" method of GerritPatch.
This is necessary because GerritPatch overrides the GerritDependencies method.
TARGET = 'chromite.lib.patch.GerritPatch'
ATTRS = ('GerritDependencies',)
# pylint: disable=protected-access
# pylint: disable=too-many-ancestors
class PatchSeriesTestCase(patch_unittest.UploadedLocalPatchTestCase,
"""Base class for tests that need to test PatchSeries."""
def _ValidateTransactionCall(self, _changes):
def setUp(self):
self._patch_factory = patch_unittest.MockPatchFactory()
self.build_root = 'fakebuildroot'
self.GetPatches = self._patch_factory.GetPatches
self.MockPatch = self._patch_factory.MockPatch
def MakeHelper(self, cros_internal=None, cros=None):
# pylint: disable=attribute-defined-outside-init
site_params = config_lib.GetSiteParams()
if cros_internal:
cros_internal = mock.create_autospec(gerrit.GerritHelper)
cros_internal.version = '2.2'
cros_internal.remote = site_params.INTERNAL_REMOTE
if cros:
cros = mock.create_autospec(gerrit.GerritHelper)
cros.remote = site_params.EXTERNAL_REMOTE
cros.version = '2.2'
return patch_series.HelperPool(cros_internal=cros_internal,
def GetPatchSeries(self, helper_pool=None):
if helper_pool is None:
helper_pool = self.MakeHelper(cros_internal=True, cros=True)
series = patch_series.PatchSeries(self.build_root, helper_pool)
# Suppress transactions.
series._Transaction = self._ValidateTransactionCall
series.GetGitRepoForChange = \
lambda change, **kwargs: os.path.join(self.build_root, change.project)
return series
def CheckPatchApply(self, apply_mocks):
for apply_mock in apply_mocks:
apply_mock.assert_called_once_with(mock.ANY, trivial=False)
value = apply_mock.call_args[0][0]
self.assertTrue(isinstance(value, MockManifest))
self.assertEqual(value.root, self.build_root)
def SetPatchApply(self, patch):
return self.PatchObject(patch, 'ApplyAgainstManifest')
def assertResults(self, series, changes, applied=(), failed_tot=(),
failed_inflight=(), frozen=True):
manifest = MockManifest(self.build_root)
result = series.Apply(changes, frozen=frozen, manifest=manifest)
_GetIds = lambda seq: [ for x in seq]
_GetFailedIds = lambda seq: _GetIds(x.patch for x in seq)
applied_result = _GetIds(result[0])
failed_tot_result, failed_inflight_result = [
_GetFailedIds(x) for x in result[1:]]
applied = _GetIds(applied)
failed_tot = _GetIds(failed_tot)
failed_inflight = _GetIds(failed_inflight)
self.assertEqual(applied, applied_result)
self.assertCountEqual(failed_inflight, failed_inflight_result)
self.assertCountEqual(failed_tot, failed_tot_result)
return result
class TestUploadedLocalPatch(PatchSeriesTestCase):
"""Test the interaction between uploaded local git patches and PatchSeries."""
def testFetchChanges(self):
"""Test fetching uploaded local patches."""
git1, git2, patch1 = self._CommonGitSetup()
patch2 = self.CommitFile(git1, 'monkeys2', 'foon2')
patch3 = self._MkPatch(git1, None, original_sha1=patch1.sha1)
patch4 = self._MkPatch(git1, None, original_sha1=patch2.sha1)
series = self.GetPatchSeries()
series.GetGitRepoForChange = lambda change, **kwargs: git2
patches, _ = series.FetchChanges([patch3, patch4])
self.assertEqual(len(patches), 2)
def testFetchChangesWithChangeNotInManifest(self):
"""test FetchChanges with ChangeNotInManifest."""
# pylint: disable=unused-argument
def raiseException(change, **kwargs):
raise cros_patch.ChangeNotInManifest(change)
patch_1, patch_2 = patches = self.GetPatches(2)
series = self.GetPatchSeries()
series.GetGitRepoForChange = raiseException
changes, not_in_manifest = series.FetchChanges(patches)
self.assertEqual(len(changes), 0)
self.assertEqual(len(not_in_manifest), 2)
self.assertEqual(not_in_manifest[0].patch, patch_1)
self.assertEqual(not_in_manifest[1].patch, patch_2)