blob: 4f0d1cd5217ff0c9028b9fed1efea7fa3dbee38a [file] [log] [blame]
#!/usr/bin/python
# 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.
"""This module tests the cros image command."""
import copy
import mock
import os
import shutil
import sys
sys.path.insert(0, os.path.abspath('%s/../../..' % os.path.dirname(__file__)))
from chromite.buildbot import constants
from chromite.cros.commands import cros_chrome_sdk
from chromite.cros.commands import init_unittest
from chromite.lib import cache
from chromite.lib import cros_test_lib
from chromite.lib import gclient
from chromite.lib import gs
from chromite.lib import gs_unittest
from chromite.lib import osutils
from chromite.lib import partial_mock
class MockChromeSDKCommand(init_unittest.MockCommand):
"""Mock out the build command."""
TARGET = 'chromite.cros.commands.cros_chrome_sdk.ChromeSDKCommand'
TARGET_CLASS = cros_chrome_sdk.ChromeSDKCommand
COMMAND = 'chrome-sdk'
class ParserTest(cros_test_lib.MockTempDirTestCase):
"""Test the parser."""
def testNormal(self):
"""Tests that our example parser works normally."""
with MockChromeSDKCommand(
['--board', SDKFetcherMock.BOARD],
base_args=['--cache-dir', self.tempdir]) as bootstrap:
self.assertEquals(bootstrap.inst.options.board, SDKFetcherMock.BOARD)
self.assertEquals(bootstrap.inst.options.cache_dir, self.tempdir)
def _GSCopyMock(_self, path, dest):
"""Used to simulate a GS Copy operation."""
with osutils.TempDirContextManager() as tempdir:
local_path = os.path.join(tempdir, os.path.basename(path))
osutils.Touch(local_path)
shutil.move(local_path, dest)
def _DependencyMockCtx(f):
"""Attribute that ensures dependency PartialMocks are started.
Since PartialMock does not support nested mocking, we need to first call
stop() on the outer level PartialMock (which is passed in to us). We then
re-start() the outer level upon exiting the context.
"""
def new_f(self, *args, **kwargs):
if not self.entered:
try:
self.entered = True
# Temporarily disable outer GSContext mock before starting our mock.
# TODO(rcui): Generalize this attribute and include in partial_mock.py.
if self.ext_gs_mock:
self.ext_gs_mock.stop()
with self.gs_mock:
return f(self, *args, **kwargs)
finally:
self.entered = False
if self.ext_gs_mock:
self.ext_gs_mock.start()
else:
return f(self, *args, **kwargs)
return new_f
class SDKFetcherMock(partial_mock.PartialMock):
"""Provides mocking functionality for SDKFetcher."""
TARGET = 'chromite.cros.commands.cros_chrome_sdk.SDKFetcher'
ATTRS = ('__init__', '_GetChromeLKGM', '_GetNewestManifestVersion',
'_UpdateTarball', '_GetMetadata')
FAKE_METADATA = """
{
"boards": ["x86-alex"],
"cros-version": "25.3543.2",
"metadata-version": "1",
"bot-hostname": "build82-m2.golo.chromium.org",
"bot-config": "x86-alex-release",
"toolchain-tuple": ["i686-pc-linux-gnu"],
"toolchain-url": "2013/01/%(target)s-2013.01.23.003823.tar.xz",
"sdk-version": "2013.01.23.003823"
}"""
BOARD = 'x86-alex'
VERSION = 'R25-3543.2.0'
def __init__(self, gs_mock=None):
"""Initializes the mock.
Arguments:
gs_mock: An already started GSContextMock instance. stop() will be called
on this instance every time execution enters one our the mocked out
methods, and start() called on it once execution leaves the mocked out
method.
"""
partial_mock.PartialMock.__init__(self)
self.ext_gs_mock = gs_mock
self.entered = False
self.gs_mock = gs_unittest.GSContextMock()
self.gs_mock.SetDefaultCmdResult()
@_DependencyMockCtx
def _target__init__(self, inst, *args, **kwargs):
self.backup['__init__'](inst, *args, **kwargs)
if not inst.cache_base.startswith('/tmp'):
raise AssertionError('For testing, SDKFetcher cache_dir needs to be a '
'dir under /tmp')
@_DependencyMockCtx
def _GetChromeLKGM(self, _inst, *_args, **_kwargs):
return None
@_DependencyMockCtx
def _GetNewestManifestVersion(self, _inst, *_args, **_kwargs):
return self.VERSION
@_DependencyMockCtx
def _UpdateTarball(self, inst, *args, **kwargs):
with mock.patch.object(gs.GSContext, 'Copy', autospec=True,
side_effect=_GSCopyMock):
with mock.patch.object(cache, 'Untar'):
return self.backup['_UpdateTarball'](inst, *args, **kwargs)
@_DependencyMockCtx
def _GetMetadata(self, inst, *args, **kwargs):
self.gs_mock.SetDefaultCmdResult()
self.gs_mock.AddCmdResult(
partial_mock.ListRegex('cat .*/%s' % constants.METADATA_JSON),
output=self.FAKE_METADATA)
return self.backup['_GetMetadata'](inst, *args, **kwargs)
class RunThroughTest(cros_test_lib.MockTempDirTestCase):
"""Run the script with most things mocked out."""
VERSION_KEY = (SDKFetcherMock.BOARD, SDKFetcherMock.VERSION,
constants.CHROME_SYSROOT_TAR)
FAKE_ENV = {
'GYP_DEFINES': "sysroot='/path/to/sysroot'",
'CXX': 'x86_64-cros-linux-gnu-g++ -B /path/to/gold',
'CC': 'x86_64-cros-linux-gnu-gcc -B /path/to/gold',
'LD': 'x86_64-cros-linux-gnu-g++ -B /path/to/gold',
}
def setUp(self):
self.sdk_mock = self.StartPatcher(SDKFetcherMock())
self.cmd_mock = MockChromeSDKCommand(
['--board', SDKFetcherMock.BOARD, 'true'],
base_args=['--cache-dir', self.tempdir])
self.StartPatcher(self.cmd_mock)
self.cmd_mock.UnMockAttr('Run')
self.PatchObject(osutils, 'SourceEnvironment',
autospec=True, return_value=copy.copy(self.FAKE_ENV))
@property
def cache(self):
return self.cmd_mock.inst.sdk.tarball_cache
def testIt(self):
"""Test a runthrough of the script."""
self.cmd_mock.inst.Run()
with self.cache.Lookup(self.VERSION_KEY) as r:
self.assertTrue(r.Exists())
def testSpecificComponent(self):
"""Tests that SDKFetcher.Prepare() handles |components| param properly."""
sdk = cros_chrome_sdk.SDKFetcher(os.path.join(self.tempdir),
SDKFetcherMock.BOARD)
components = [constants.BASE_IMAGE_TAR, constants.CHROME_SYSROOT_TAR]
with sdk.Prepare(components=components) as ctx:
for c in components:
self.assertTrue(os.path.exists(ctx.key_map[c].path))
for c in [constants.IMAGE_SCRIPTS_TAR, constants.CHROME_ENV_TAR]:
self.assertFalse(c in ctx.key_map)
class VersionTest(cros_test_lib.MockTempDirTestCase):
"""Tests the determination of which SDK version to use."""
PARTIAL_VERSION = '3543.2.0'
VERSION = 'RXX-%s' % PARTIAL_VERSION
ENV_VERSION = 'RYY-%s' % PARTIAL_VERSION
BOARD = 'lumpy'
VERSION_BASE = ("gs://chromeos-image-archive/%s-release/%s"
% (BOARD, VERSION))
FAKE_LS = """\
%(base)s/UPLOADED
%(base)s/au-generator.zip
%(base)s/autotest.tar
%(base)s/bootloader.tar.xz
""" % {'base': VERSION_BASE}
def setUp(self):
self.gs_mock = self.StartPatcher(gs_unittest.GSContextMock())
self.gs_mock.SetDefaultCmdResult()
self.sdk_mock = self.StartPatcher(SDKFetcherMock(gs_mock=self.gs_mock))
self.sdk_mock.UnMockAttr('_GetChromeLKGM')
os.environ.pop(cros_chrome_sdk.SDKFetcher.SDK_VERSION_ENV, None)
self.sdk = cros_chrome_sdk.SDKFetcher(
os.path.join(self.tempdir, 'cache'), self.BOARD)
def testChromeVersion(self):
"""We pick up the right LKGM version from the Chrome tree."""
gclient_root = os.path.join(self.tempdir, 'gclient_root')
self.PatchObject(gclient, 'FindGclientCheckoutRoot',
return_value=gclient_root)
self.gs_mock.AddCmdResult(
partial_mock.ListRegex('ls .*-%s' % self.PARTIAL_VERSION),
output=self.FAKE_LS)
lkgm_file = os.path.join(gclient_root, constants.PATH_TO_CHROME_LKGM)
osutils.Touch(lkgm_file, makedirs=True)
osutils.WriteFile(lkgm_file, self.PARTIAL_VERSION)
self.sdk.UpdateDefaultVersion()
self.assertEquals(self.sdk.GetDefaultVersion(),
self.VERSION)
# pylint: disable=E1101
self.assertTrue(gclient.FindGclientCheckoutRoot.called)
def testDefaultEnvBadBoard(self):
"""We don't use the version in the environment if board doesn't match."""
os.environ[cros_chrome_sdk.SDKFetcher.SDK_VERSION_ENV] = self.ENV_VERSION
self.assertEquals(self.sdk.GetDefaultVersion(), self.sdk_mock.VERSION)
def testDefaultEnvGoodBoard(self):
"""We use the version in the environment if board matches."""
os.environ[cros_chrome_sdk.SDKFetcher.SDK_VERSION_ENV] = self.ENV_VERSION
os.environ[cros_chrome_sdk.SDKFetcher.SDK_BOARD_ENV] = self.BOARD
self.assertEquals(self.sdk.GetDefaultVersion(), self.ENV_VERSION)
if __name__ == '__main__':
cros_test_lib.main()