blob: 0a17c951bb63e93ac8a0dd3b5edcc0fbb2973e80 [file] [log] [blame]
# 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.
"""Unit tests for cros_mark_android_as_stable.py."""
import builtins
import os
from chromite.lib import constants
from chromite.lib import cros_build_lib
from chromite.lib import cros_test_lib
from chromite.lib import gs
from chromite.lib import gs_unittest
from chromite.lib import osutils
from chromite.lib import portage_util
from chromite.scripts import cros_mark_android_as_stable
from chromite.service import android
pytestmark = cros_test_lib.pytestmark_inside_only
class CrosMarkAndroidAsStable(cros_test_lib.MockTempDirTestCase):
"""Tests for cros_mark_android_as_stable."""
unstable_data = 'KEYWORDS="~x86 ~arm"'
stable_data = 'KEYWORDS="x86 arm"'
STAT_OUTPUT = """%s:
Creation time: Sat, 23 Aug 2014 06:53:20 GMT
Content-Language: en
Content-Length: 74
Content-Type: application/octet-stream
Hash (crc32c): BBPMPA==
Hash (md5): ms+qSYvgI9SjXn8tW/5UpQ==
ETag: CNCgocbmqMACEAE=
Generation: 1408776800850000
Metageneration: 1
"""
def setUp(self):
"""Setup vars and create mock dir."""
self.android_package = constants.ANDROID_PI_PACKAGE
self.tmp_overlay = os.path.join(self.tempdir, 'private-overlays',
'project-cheets-private')
self.mock_android_dir = android.GetAndroidPackageDir(
self.android_package, overlay_dir=self.tmp_overlay)
ebuild = os.path.join(self.mock_android_dir,
self.android_package + '-%s.ebuild')
self.unstable = ebuild % '9999'
self.old_version = '25'
self.old = ebuild % ('%s-r1' % self.old_version)
self.old2_version = '50'
self.old2 = ebuild % ('%s-r1' % self.old2_version)
self.new_version = '100'
self.new = ebuild % ('%s-r1' % self.new_version)
osutils.WriteFile(self.unstable, self.unstable_data, makedirs=True)
osutils.WriteFile(self.old, self.stable_data, makedirs=True)
osutils.WriteFile(self.old2, self.stable_data, makedirs=True)
self.build_branch = constants.ANDROID_PI_BUILD_BRANCH
self.gs_mock = self.StartPatcher(gs_unittest.GSContextMock())
self.arc_bucket_url = 'gs://a'
self.runtime_artifacts_bucket_url = 'gs://r'
def setupMockRuntimeDataBuild(self, android_version):
"""Helper to mock a build for runtime data."""
def _RaiseGSNoSuchKey(*_args, **_kwargs):
raise gs.GSNoSuchKey('file does not exist')
archs = ['arm', 'arm64', 'x86', 'x86_64']
build_types = ['user', 'userdebug']
runtime_datas = ['gms_core_cache', 'ureadahead_pack']
for arch in archs:
for build_type in build_types:
for runtime_data in runtime_datas:
path = (f'{self.runtime_artifacts_bucket_url}/{runtime_data}_{arch}_'
f'{build_type}_{android_version}.tar')
self.gs_mock.AddCmdResult(['stat', '--', path],
side_effect=_RaiseGSNoSuchKey)
pin_path = (f'{self.runtime_artifacts_bucket_url}/'
f'{constants.ANDROID_PI_BUILD_BRANCH}_pin_version')
self.gs_mock.AddCmdResult(['stat', '--', pin_path],
side_effect=_RaiseGSNoSuchKey)
def testFindAndroidCandidates(self):
"""Test creation of stable ebuilds from mock dir."""
(unstable, stable) = cros_mark_android_as_stable.FindAndroidCandidates(
self.mock_android_dir)
stable_ebuild_paths = [x.ebuild_path for x in stable]
self.assertEqual(unstable.ebuild_path, self.unstable)
self.assertEqual(len(stable), 2)
self.assertIn(self.old, stable_ebuild_paths)
self.assertIn(self.old2, stable_ebuild_paths)
def testMarkAndroidEBuildAsStable(self):
"""Test updating of ebuild."""
self.PatchObject(cros_build_lib, 'run')
self.PatchObject(portage_util.EBuild, 'GetCrosWorkonVars',
return_value=None)
stable_candidate = portage_util.EBuild(self.old2)
unstable = portage_util.EBuild(self.unstable)
android_version = self.new_version
package_dir = self.mock_android_dir
self.setupMockRuntimeDataBuild(android_version)
revved = cros_mark_android_as_stable.MarkAndroidEBuildAsStable(
stable_candidate, unstable, self.android_package, android_version,
package_dir, self.build_branch, self.arc_bucket_url,
self.runtime_artifacts_bucket_url)
self.assertIsNotNone(revved)
version_atom, files_to_add, files_to_remove = revved
self.assertEqual(
version_atom,
f'chromeos-base/{self.android_package}-{self.new_version}-r1')
self.assertEqual(files_to_add,
[self.new, os.path.join(package_dir, 'Manifest')])
self.assertEqual(files_to_remove, [self.old2])
def testUpdateDataCollectorArtifacts(self):
android_version = 100
# Mock by default runtime artifacts are not found.
self.setupMockRuntimeDataBuild(android_version)
# Override few as existing.
path1 = (f'{self.runtime_artifacts_bucket_url}/ureadahead_pack_x86_64_'
f'user_{android_version}.tar')
self.gs_mock.AddCmdResult(['stat', '--', path1],
stdout=(self.STAT_OUTPUT) % path1)
path2 = (f'{self.runtime_artifacts_bucket_url}/gms_core_cache_arm_'
f'userdebug_{android_version}.tar')
self.gs_mock.AddCmdResult(['stat', '--', path2],
stdout=(self.STAT_OUTPUT) % path2)
variables = cros_mark_android_as_stable.UpdateDataCollectorArtifacts(
android_version,
self.runtime_artifacts_bucket_url,
constants.ANDROID_PI_BUILD_BRANCH)
version_reference = '${PV}'
expectation1 = (f'{self.runtime_artifacts_bucket_url}/'
f'ureadahead_pack_x86_64_user_{version_reference}.tar')
expectation2 = (f'{self.runtime_artifacts_bucket_url}/'
f'gms_core_cache_arm_userdebug_{version_reference}.tar')
self.assertEqual({
'X86_64_USER_UREADAHEAD_PACK': expectation1,
'ARM_USERDEBUG_GMS_CORE_CACHE': expectation2,
}, variables)
def testUpdateDataCollectorArtifactsPin(self):
android_version = 100
android_pin_version = 50
# Mock by default runtime artifacts are not found.
self.setupMockRuntimeDataBuild(android_version)
self.setupMockRuntimeDataBuild(android_pin_version)
# Override few as existing.
path1 = (f'{self.runtime_artifacts_bucket_url}/ureadahead_pack_x86_64_'
f'user_{android_pin_version}.tar')
self.gs_mock.AddCmdResult(['stat', '--', path1],
stdout=(self.STAT_OUTPUT) % path1)
path2 = (f'{self.runtime_artifacts_bucket_url}/gms_core_cache_arm_'
f'userdebug_{android_pin_version}.tar')
self.gs_mock.AddCmdResult(['stat', '--', path2],
stdout=(self.STAT_OUTPUT) % path2)
pin_path = (f'{self.runtime_artifacts_bucket_url}/'
f'{constants.ANDROID_PI_BUILD_BRANCH}_pin_version')
self.gs_mock.AddCmdResult(['stat', '--', pin_path],
stdout=(self.STAT_OUTPUT) % pin_path)
self.gs_mock.AddCmdResult(['cat', pin_path],
stdout=str(android_pin_version))
variables = cros_mark_android_as_stable.UpdateDataCollectorArtifacts(
android_version,
self.runtime_artifacts_bucket_url,
constants.ANDROID_PI_BUILD_BRANCH)
version_reference = '50'
expectation1 = (f'{self.runtime_artifacts_bucket_url}/'
f'ureadahead_pack_x86_64_user_{version_reference}.tar')
expectation2 = (f'{self.runtime_artifacts_bucket_url}/'
f'gms_core_cache_arm_userdebug_{version_reference}.tar')
self.assertEqual({
'X86_64_USER_UREADAHEAD_PACK': expectation1,
'ARM_USERDEBUG_GMS_CORE_CACHE': expectation2,
}, variables)
def testMainRevved(self):
android_version = self.new_version
self.PatchObject(cros_build_lib, 'run')
self.PatchObject(portage_util.EBuild, 'GetCrosWorkonVars',
return_value=None)
self.setupMockRuntimeDataBuild(android_version)
mock_mirror_artifacts = self.PatchObject(android, 'MirrorArtifacts',
return_value=android_version)
mock_print = self.PatchObject(builtins, 'print')
android_bucket_url = 'gs://ab'
cros_mark_android_as_stable.main([
'--android_bucket_url', android_bucket_url,
'--android_build_branch', self.build_branch,
'--android_package', self.android_package,
'--arc_bucket_url', self.arc_bucket_url,
'--force_version', android_version,
'--srcroot', self.tempdir,
'--runtime_artifacts_bucket_url', self.runtime_artifacts_bucket_url,
'--skip_commit',
])
mock_mirror_artifacts.assert_called_once_with(android_bucket_url,
self.build_branch,
self.arc_bucket_url,
self.mock_android_dir,
android_version)
# pylint: disable=line-too-long
mock_print.assert_called_once_with('\n{"android_atom": "chromeos-base/android-container-pi-100-r1", "modified_files": ["chromeos-base/android-container-pi/android-container-pi-100-r1.ebuild", "chromeos-base/android-container-pi/Manifest", "chromeos-base/android-container-pi/android-container-pi-50-r1.ebuild"], "revved": true}')
def testMainNotRevved(self):
android_version = self.old2_version
# Mock to create a stable ebuild identical to the original.
def MockMarkAsStable(_unstable_path, new_stable_path, _vars, **_kwargs):
osutils.WriteFile(new_stable_path, self.stable_data)
self.PatchObject(portage_util.EBuild, 'GetCrosWorkonVars',
return_value=None)
self.PatchObject(portage_util.EBuild, 'MarkAsStable',
side_effect=MockMarkAsStable)
self.setupMockRuntimeDataBuild(android_version)
mock_mirror_artifacts = self.PatchObject(android, 'MirrorArtifacts',
return_value=android_version)
mock_print = self.PatchObject(builtins, 'print')
android_bucket_url = 'gs://ab'
cros_mark_android_as_stable.main([
'--android_bucket_url', android_bucket_url,
'--android_build_branch', self.build_branch,
'--android_package', self.android_package,
'--arc_bucket_url', self.arc_bucket_url,
'--force_version', android_version,
'--srcroot', self.tempdir,
'--runtime_artifacts_bucket_url', self.runtime_artifacts_bucket_url,
'--skip_commit',
])
mock_mirror_artifacts.assert_called_once_with(android_bucket_url,
self.build_branch,
self.arc_bucket_url,
self.mock_android_dir,
android_version)
mock_print.assert_called_once_with('\n{"revved": false}')
def testMainUpdateLKGB(self):
"""Tests a successful LKGB update without an actual uprev."""
android_version = 'android-version'
old_version = 'old-version'
self.PatchObject(cros_mark_android_as_stable, '_PrepareGitBranch')
mock_commit = self.PatchObject(cros_mark_android_as_stable, '_CommitChange')
self.PatchObject(android, 'ReadLKGB', return_value=old_version)
mock_write_lkgb = self.PatchObject(android, 'WriteLKGB')
mock_mirror_artifacts = self.PatchObject(android, 'MirrorArtifacts')
mock_mark_as_stable = self.PatchObject(portage_util.EBuild, 'MarkAsStable')
cros_mark_android_as_stable.main([
'--android_package', self.android_package,
'--force_version', android_version,
'--srcroot', self.tempdir,
'--update_lkgb',
])
mock_write_lkgb.assert_called_once_with(self.mock_android_dir,
android_version)
mock_commit.assert_called_once()
mock_mirror_artifacts.assert_not_called()
mock_mark_as_stable.assert_not_called()
def testMainUpdateLKGBMissingLKGB(self):
"""Tests LKGB update when LKGB file is currently missing."""
android_version = 'android-version'
self.PatchObject(cros_mark_android_as_stable, '_PrepareGitBranch')
mock_commit = self.PatchObject(cros_mark_android_as_stable, '_CommitChange')
self.PatchObject(android, 'ReadLKGB',
side_effect=android.MissingLKGBError())
mock_write_lkgb = self.PatchObject(android, 'WriteLKGB')
cros_mark_android_as_stable.main([
'--android_package', self.android_package,
'--force_version', android_version,
'--srcroot', self.tempdir,
'--update_lkgb',
])
mock_write_lkgb.assert_called_once_with(self.mock_android_dir,
android_version)
mock_commit.assert_called_once()
def testMainUpdateLKGBInvalidLKGB(self):
"""Tests LKGB update when current LKGB file is invalid."""
android_version = 'android-version'
self.PatchObject(cros_mark_android_as_stable, '_PrepareGitBranch')
mock_commit = self.PatchObject(cros_mark_android_as_stable, '_CommitChange')
self.PatchObject(android, 'ReadLKGB',
side_effect=android.InvalidLKGBError())
mock_write_lkgb = self.PatchObject(android, 'WriteLKGB')
cros_mark_android_as_stable.main([
'--android_package', self.android_package,
'--force_version', android_version,
'--srcroot', self.tempdir,
'--update_lkgb',
])
mock_write_lkgb.assert_called_once_with(self.mock_android_dir,
android_version)
mock_commit.assert_called_once()
def testMainUpdateLKGBNoUpdate(self):
"""Tests if nothing happens when LKGB is left unchanged."""
android_version = 'old-version'
old_version = 'old-version'
self.PatchObject(cros_mark_android_as_stable, '_PrepareGitBranch')
mock_commit = self.PatchObject(cros_mark_android_as_stable, '_CommitChange')
self.PatchObject(android, 'ReadLKGB', return_value=old_version)
mock_write_lkgb = self.PatchObject(android, 'WriteLKGB')
cros_mark_android_as_stable.main([
'--android_package', self.android_package,
'--force_version', android_version,
'--srcroot', self.tempdir,
'--update_lkgb',
])
mock_write_lkgb.assert_not_called()
mock_commit.assert_not_called()
def testMainUpdateLKGBWithoutVersion(self):
"""Tests when --force_version flag is missing during LKGB update."""
self.PatchObject(cros_mark_android_as_stable, '_PrepareGitBranch')
with self.assertRaises(Exception):
cros_mark_android_as_stable.main([
'--android_package', self.android_package,
'--srcroot', self.tempdir,
'--update_lkgb',
])
def testMainUpdateLKGBSkipCommit(self):
"""Tests when --skip_commit is set during LKGB update."""
android_version = 'android-version'
old_version = 'old-version'
mock_commit = self.PatchObject(cros_mark_android_as_stable, '_CommitChange')
self.PatchObject(android, 'ReadLKGB', return_value=old_version)
mock_write_lkgb = self.PatchObject(android, 'WriteLKGB')
cros_mark_android_as_stable.main([
'--android_package', self.android_package,
'--force_version', android_version,
'--srcroot', self.tempdir,
'--skip_commit',
'--update_lkgb',
])
mock_write_lkgb.assert_called_once_with(self.mock_android_dir,
android_version)
mock_commit.assert_not_called()