blob: b5a98ce5fbad607e704998c7a2f964198c4941f7 [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.
"""Unit tests for build_artifact module.
These unit tests take tarball from google storage locations to fully test
the artifact download process. Please make sure to set up your boto file.
"""
import itertools
import os
import random
import shutil
import tempfile
from unittest import mock
from chromite.lib import cros_test_lib
from chromite.lib import gs_unittest
from chromite.lib.xbuddy import artifact_info
from chromite.lib.xbuddy import build_artifact
from chromite.lib.xbuddy import devserver_constants
from chromite.lib.xbuddy import downloader
pytestmark = cros_test_lib.pytestmark_inside_only
_VERSION = "R80-12653.0.0-rc1"
_BUILDER = "amd64-generic-full"
_TEST_GOLO_BUILD_ID = "%s/%s" % (_BUILDER, _VERSION)
_TEST_GOLO_ARCHIVE = "gs://chromeos-image-archive/" + _TEST_GOLO_BUILD_ID
_TEST_NON_EXISTING_GOLO_BUILD_ID = "amd64-generic-full/R26-no_such_build"
_TEST_NON_EXISTING_GOLO_ARCHIVE = (
"gs://chromeos-image-archive/" + _TEST_NON_EXISTING_GOLO_BUILD_ID
)
_TEST_GOLO_ARCHIVE_TEST_TARBALL_CONTENT = [
"autotest/test_suites/control.youtube_mse_eme",
"autotest/test_suites/control.wifi_stress",
"autotest/test_suites/control.wifi_endtoend",
"autotest/test_suites/control.chameleon_hdmi_stress",
"autotest/test_suites/control.enroll_retainment",
"autotest/test_suites/control.wifi_interop_static",
"autotest/test_suites/control.gce-smoke",
"autotest/test_suites/control.power_requirements",
"autotest/test_suites/control.hardware_storagequal",
"autotest/test_suites/control.bluetooth_qualification",
"autotest/test_suites/control.gpu_hang",
"autotest/test_suites/control.faft_lab",
"autotest/test_suites/control.AFDO_record",
"autotest/test_suites/control.faft_lv5",
"autotest/test_suites/control.link_perf",
"autotest/test_suites/control.stub",
"autotest/test_suites/control.fingerprint",
"autotest/test_suites/control.cellular_pseudomodem",
"autotest/test_suites/control.wifi_release",
"autotest/test_suites/control.regression",
"autotest/test_suites/control.check_setup_storage_qual",
"autotest/test_suites/control.chameleon_audio_perbuild",
"autotest/test_suites/control.brillo-bvt",
"autotest/test_suites/control.usb-camera",
"autotest/test_suites/control.wilco_bve",
"autotest/test_suites/control.wifi_tdls_cast",
"autotest/test_suites/control.cellular_ota_verizon",
"autotest/test_suites/control.chrome-informational",
"autotest/test_suites/control.security",
"autotest/test_suites/control.faft_pd",
"autotest/test_suites/control.video",
"autotest/test_suites/control.ent-wificell",
"autotest/test_suites/control.wifi_interop_wpa2",
"autotest/test_suites/control.chameleon_audio_unstable",
"autotest/test_suites/control.paygen_au_beta",
"autotest/test_suites/control.bluetooth_sanity",
"autotest/test_suites/control.vmtest_informational4",
"autotest/test_suites/control.faft_ec",
"autotest/test_suites/control.kernel_daily_benchmarks",
"autotest/test_suites/control.wifi_perf",
"autotest/test_suites/control.faft_ec_au_2",
"autotest/test_suites/control.bluetooth_standalone",
"autotest/test_suites/control.moblab_quick",
"autotest/test_suites/control.telemetry_unit_server",
"autotest/test_suites/control.faft_smoke",
"autotest/test_suites/control.vmtest_informational1",
"autotest/test_suites/control.audio",
"autotest/test_suites/control.faft_lv3",
"autotest/test_suites/control.touch",
"autotest/test_suites/control.cellular_endtoend",
"autotest/test_suites/control.faft_setup",
"autotest/test_suites/control.faft_bios_tot",
"autotest/test_suites/control.graphics_per-build",
"autotest/test_suites/control.cellular_au_nightly",
"autotest/test_suites/control.vmtest_informational2",
"autotest/test_suites/control.faft_normal",
"autotest/test_suites/control.crosbolt_perf_weekly",
"autotest/test_suites/control.sb65-presubmit",
"autotest/test_suites/control.paygen_au_canary",
"autotest/test_suites/control.bluetooth_stress",
"autotest/test_suites/control.bvt-cq",
"autotest/test_suites/control.au-perbuild",
"autotest/test_suites/control.brillo-experimental",
"autotest/test_suites/control.moblab_storage_qual",
"autotest/test_suites/control.power_measurement_wrapper",
"autotest/test_suites/control.deqp",
"autotest/test_suites/control.kiosk_longevity",
"autotest/test_suites/control.faft_ec_au_1",
"autotest/test_suites/control.faft_lv4",
"autotest/test_suites/control.power_loadtest_fast",
"autotest/test_suites/control.bluetooth",
"autotest/test_suites/control.bvt-tast-cq",
"autotest/test_suites/control.cellular_ota",
"autotest/test_suites/control.powerplay",
"autotest/test_suites/control.power_loadtest_1hour",
"autotest/test_suites/control.stubflake",
"autotest/test_suites/control.bluetooth_flaky",
"autotest/test_suites/control.wifichaos",
"autotest/test_suites/control.faft_ec_au_3",
"autotest/test_suites/control.graphics_system",
"autotest/test_suites/control.provision",
"autotest/test_suites/control.cups_weekly",
"autotest/test_suites/control.bvt-tast-chrome-pfq",
"autotest/test_suites/control.bluestreak-pre-cq",
"autotest/test_suites/control.bvt-perbuild",
"autotest/test_suites/control.au_fsi",
"autotest/test_suites/control.faft_cr50_prepvt",
"autotest/test_suites/control.bvt-tast-android-pfq",
"autotest/test_suites/control.hardware_memoryqual",
"autotest/test_suites/control.sanity",
"autotest/test_suites/control.brillo-postsubmit",
"autotest/test_suites/control.hardware_storagequal_cq",
"autotest/test_suites/control.hardware_memoryqual_quick",
"autotest/test_suites/control.faft_infra",
"autotest/test_suites/control.wifi_matfunc_bcm4356",
"autotest/test_suites/control.gts",
"autotest/test_suites/control.stub_server_nossp",
"autotest/test_suites/control.faft_lv2",
"autotest/test_suites/control.faft_bios_au_2",
"autotest/test_suites/control.faft_lv1",
"autotest/test_suites/control.av_webcam",
"autotest/test_suites/control.power_sanity",
"autotest/test_suites/control.wificell-pre-cq",
"autotest/test_suites/control.hotrod",
"autotest/test_suites/control.skylab_staging_test",
"autotest/test_suites/control.perfalerts",
"autotest/test_suites/control.bvt-installer",
"autotest/test_suites/control.graphics_browser",
"autotest/test_suites/control.network_nightly",
"autotest/test_suites/control.moblab",
"autotest/test_suites/control.ent-nightly",
"autotest/test_suites/control.kernel_weekly_regression",
"autotest/test_suites/control.crosbolt_perf_perbuild",
"autotest/test_suites/control.wifi_matfunc",
"autotest/test_suites/control.hardware_storagequal_quick",
"autotest/test_suites/control.push_to_prod",
"autotest/test_suites/control.gce-sanity",
"autotest/test_suites/control.suite_attr_wrapper",
"autotest/test_suites/control.platform_test_nightly",
"autotest/test_suites/control.faft_bios_au_1",
"autotest/test_suites/control.faft_cr50_experimental",
"autotest/test_suites/control.kernel_per-build_regression",
"autotest/test_suites/control.app-compat",
"autotest/test_suites/control.jailed_build",
"autotest/test_suites/control.bvt-arc",
"autotest/test_suites/control.wifi_flaky",
"autotest/test_suites/suite_to_control_file_map",
"autotest/test_suites/control.test_that_wrapper",
"autotest/test_suites/control.experimental",
"autotest/test_suites/control.ent-perbuild",
"autotest/test_suites/control.wifi_update_router",
"autotest/test_suites/control.faft_cr50_pvt",
"autotest/test_suites/control.stress",
"autotest/test_suites/control.cellular_ota_sprint",
"autotest/test_suites/control.bvt-inline",
"autotest/test_suites/control.brillo-smoke",
"autotest/test_suites/control.faft_ec3po",
"autotest/test_suites/control.video_image_comparison_chameleon",
"autotest/test_suites/control.smoke",
"autotest/test_suites/control.moblab-cts-mini",
"autotest/test_suites/control.cellular_mbim_compliance",
"autotest/test_suites/control.kernel_daily_regression",
"autotest/test_suites/control.cellular_au",
"autotest/test_suites/control.faft_bios",
"autotest/test_suites/control.kernel_per-build_benchmarks",
"autotest/test_suites/control.usb_detect_stress",
"autotest/test_suites/control.crosbolt_perf_nightly",
"autotest/test_suites/control.tablet_mode",
"autotest/test_suites/control.bluetooth_wifi_coex",
"autotest/test_suites/control.youtube_page",
"autotest/test_suites/control.faft_dev",
"autotest/test_suites/control.storagequal",
"autotest/test_suites/control.wifi_atten_perf",
"autotest/test_suites/control.cr50_stress",
"autotest/test_suites/control.cellular_ota_tmobile",
"autotest/test_suites/control.wifi_interop",
"autotest/test_suites/control.arc-unit-test",
"autotest/test_suites/control.bluestreak-partners",
"autotest/test_suites/control.chameleon_hdmi_unstable",
"autotest/test_suites/control.graphics",
"autotest/test_suites/control.cros_test_platform",
"autotest/test_suites/control.faft_cr50_tot",
"autotest/test_suites/control.network_ui",
"autotest/test_suites/control.brillo-presubmit",
"autotest/test_suites/control.graphics_per-week",
"autotest/test_suites/control.usb_detect",
"autotest/test_suites/control.partners",
"autotest/test_suites/control.faft_ec_tot",
"autotest/test_suites/control.check_setup_cts_N",
"autotest/test_suites/control.tendo_experimental",
"autotest/test_suites/control.power_idle",
"autotest/test_suites/control.vmtest_informational3",
"autotest/test_suites/control.faft_bios_au_3",
"autotest/test_suites/control.stub_server",
"autotest/test_suites/control.cts_P",
"autotest/test_suites/control.bluetooth_e2e",
"autotest/test_suites/control.power_daily",
"autotest/test_suites/control.cellular_ota_att",
"autotest/test_suites/dependency_info",
"autotest/test_suites/control.power_loadtest",
"autotest/test_suites/control.chameleon_hdmi_perbuild",
"autotest/test_suites/control.cellular_modem_repair",
"autotest/test_suites/control.faft_wilco",
"autotest/test_suites/control.graphics_per-day",
"autotest/test_suites/control.manual_platform_suite",
"autotest/test_suites/control.hardware_storagequal_temp",
"autotest/test_suites/control.paygen_au_dev",
"autotest/test_suites/control.cros-av-analysis",
"autotest/test_suites/control.bvt-tast-informational",
"autotest/test_suites/control.brillo-audio",
"autotest/test_suites/control.cts_N",
"autotest/test_suites/control.faft_bios_ec3po",
"autotest/test_suites/control.power_build",
"autotest/test_suites/control.toolchain-tests",
"autotest/test_suites/control.security_weekly",
"autotest/test_suites/control.wifi_lucidsleep",
"autotest/test_suites/control.telemetry_unit",
"autotest/test_suites/control.paygen_au_stable",
]
_TEST_GOLO_ARCHIVE_IMAGE_ZIPFILE_CONTENT = [
"image.zip",
"unpack_partitions.sh",
"chromiumos_base_image.bin-package-sizes.json",
"config.txt",
"pack_partitions.sh",
"umount_image.sh",
"id_rsa.pub",
"boot.config",
"partition_script.sh",
"boot_images/vmlinuz-4.14.151-13598-g75d9ce1f04f5",
"boot_images/vmlinuz",
"mount_image.sh",
"id_rsa",
"license_credits.html",
"boot.desc",
]
class BuildArtifactTest(cros_test_lib.MockTestCase):
"""Test different BuildArtifact operations."""
def setUp(self) -> None:
self.work_dir = tempfile.mkdtemp("build_artifact_unittest")
self.dl = downloader.GoogleStorageDownloader(
self.work_dir, _TEST_GOLO_ARCHIVE, _TEST_GOLO_BUILD_ID
)
def tearDown(self) -> None:
shutil.rmtree(self.work_dir)
def _CheckMarker(self, marker_file, installed_files) -> None:
with open(
os.path.join(self.work_dir, marker_file), encoding="utf-8"
) as f:
self.assertEqual(installed_files, f.read().splitlines())
def testBundledArtifactTypes(self) -> None:
"""Verify all known bundled artifacts are either zip or tar files."""
known_names = ["zip", ".tgz", ".tar", "tar.bz2", "tar.xz", "tar.gz"]
for d in itertools.chain(
*build_artifact.chromeos_artifact_map.values()
):
if issubclass(d, build_artifact.BundledArtifact):
self.assertTrue(
any(d.ARTIFACT_NAME.endswith(name) for name in known_names)
)
@cros_test_lib.pytestmark_network_test
def testProcessBuildArtifact(self) -> None:
"""Processes a real tarball from GSUtil and stages it."""
artifact = build_artifact.Artifact(
build_artifact.TEST_SUITES_FILE, self.work_dir, _VERSION
)
artifact.Process(self.dl, False)
self.assertEqual(
artifact.installed_files,
[os.path.join(self.work_dir, build_artifact.TEST_SUITES_FILE)],
)
self.assertExists(
os.path.join(self.work_dir, build_artifact.TEST_SUITES_FILE)
)
self._CheckMarker(artifact.marker_name, artifact.installed_files)
@cros_test_lib.pytestmark_network_test
def testProcessTarball(self) -> None:
"""Downloads a real tarball and untars it."""
artifact = build_artifact.BundledArtifact(
build_artifact.TEST_SUITES_FILE, self.work_dir, _VERSION
)
artifact.Process(self.dl, False)
expected_installed_files = [
os.path.join(self.work_dir, filename)
for filename in (
[build_artifact.TEST_SUITES_FILE]
+ _TEST_GOLO_ARCHIVE_TEST_TARBALL_CONTENT
)
]
self.assertEqual(artifact.installed_files, expected_installed_files)
self.assertTrue(
os.path.isdir(
os.path.join(self.work_dir, "autotest", "test_suites")
)
)
self._CheckMarker(artifact.marker_name, artifact.installed_files)
@cros_test_lib.pytestmark_network_test
def testProcessTarballWithFile(self) -> None:
"""Downloads a real tarball and only untars one file from it."""
file_to_download = "autotest/test_suites/control.provision"
artifact = build_artifact.BundledArtifact(
build_artifact.TEST_SUITES_FILE,
self.work_dir,
_VERSION,
files_to_extract=[file_to_download],
)
expected_installed_files = [
os.path.join(self.work_dir, filename)
for filename in [build_artifact.TEST_SUITES_FILE]
+ [file_to_download]
]
artifact.Process(self.dl, False)
self.assertEqual(artifact.installed_files, expected_installed_files)
self.assertExists(os.path.join(self.work_dir, file_to_download))
self._CheckMarker(artifact.marker_name, artifact.installed_files)
@mock.patch.object(build_artifact.AutotestTarball, "_Extract")
@mock.patch.object(build_artifact.AutotestTarball, "_UpdateName")
@mock.patch.object(downloader.GoogleStorageDownloader, "Fetch")
@mock.patch.object(downloader.GoogleStorageDownloader, "Wait")
def testDownloadAutotest(
self, wait_mock, fetch_mock, update_name_mock, extract_mock
) -> None:
"""Downloads a real autotest tarball for test."""
artifact = build_artifact.AutotestTarball(
build_artifact.AUTOTEST_FILE,
self.work_dir,
_VERSION,
files_to_extract=None,
exclude=["autotest/test_suites"],
)
install_dir = self.work_dir
artifact.staging_dir = install_dir
rc = self.StartPatcher(cros_test_lib.RunCommandMock())
rc.SetDefaultCmdResult()
artifact.Process(self.dl, True)
self.assertFalse(artifact.installed_files)
self.assertTrue(
os.path.isdir(os.path.join(self.work_dir, "autotest", "packages"))
)
self.assertFalse(
os.path.getsize(os.path.join(self.work_dir, artifact.marker_name))
)
wait_mock.assert_called_with("autotest.tar", False, None, 1)
fetch_mock.assert_called_with("autotest.tar", install_dir + "/")
update_name_mock.assert_called()
extract_mock.assert_called()
rc.assertCommandContains(
[
"autotest/utils/packager.py",
"--action=upload",
"--repository",
os.path.join(install_dir, "autotest/packages"),
"--all",
],
cwd=install_dir,
)
@cros_test_lib.pytestmark_network_test
def testStatefulPayloadArtifact(self) -> None:
"""Tests downloading the stateful payload."""
factory = build_artifact.ChromeOSArtifactFactory(
self.work_dir, [artifact_info.STATEFUL_PAYLOAD], [], _VERSION
)
artifacts = factory.RequiredArtifacts()
self.assertEqual(len(artifacts), 1)
artifact = artifacts[0]
expected_installed_files = [
os.path.join(self.work_dir, devserver_constants.STATEFUL_FILE)
]
artifact.Process(self.dl, False)
self.assertEqual(artifact.installed_files, expected_installed_files)
for f in expected_installed_files:
self.assertExists(f)
self._CheckMarker(artifact.marker_name, artifact.installed_files)
@cros_test_lib.pytestmark_network_test
def testAUFullPayloadArtifact(self) -> None:
"""Tests downloading the full update payload."""
factory = build_artifact.ChromeOSArtifactFactory(
self.work_dir, [artifact_info.FULL_PAYLOAD], [], _VERSION
)
artifacts = factory.RequiredArtifacts()
self.assertEqual(len(artifacts), 1)
artifact = artifacts[0]
expected_installed_files = [
os.path.join(self.work_dir, f)
for f in (
devserver_constants.UPDATE_FILE,
devserver_constants.UPDATE_METADATA_FILE,
)
]
artifact.Process(self.dl, False)
self.assertEqual(artifact.installed_files, expected_installed_files)
for f in expected_installed_files:
self.assertExists(f)
self._CheckMarker(artifact.marker_name, artifact.installed_files)
@cros_test_lib.pytestmark_network_test
def testAUDeltaPayloadArtifact(self) -> None:
"""Tests downloading the delta update payload."""
factory = build_artifact.ChromeOSArtifactFactory(
self.work_dir, [artifact_info.DELTA_PAYLOAD], [], _VERSION
)
artifacts = factory.RequiredArtifacts()
self.assertEqual(len(artifacts), 1)
artifact = artifacts[0]
expected_installed_files = [
os.path.join(self.work_dir, build_artifact.AU_NTON_DIR, f)
for f in (
devserver_constants.UPDATE_FILE,
devserver_constants.UPDATE_METADATA_FILE,
)
]
artifact.Process(self.dl, False)
self.assertEqual(artifact.installed_files, expected_installed_files)
for f in expected_installed_files:
self.assertExists(f)
self._CheckMarker(artifact.marker_name, artifact.installed_files)
@cros_test_lib.pytestmark_network_test
def testImageUnzip(self) -> None:
"""Downloads and stages a zip file and extracts a test image."""
files_to_extract = ["chromiumos_test_image.bin"]
artifact = build_artifact.BundledArtifact(
build_artifact.IMAGE_FILE,
self.work_dir,
_VERSION,
files_to_extract=files_to_extract,
)
expected_installed_files = [
os.path.join(self.work_dir, filename)
for filename in [build_artifact.IMAGE_FILE] + files_to_extract
]
artifact.Process(self.dl, False)
self.assertEqual(expected_installed_files, artifact.installed_files)
for f in expected_installed_files:
self.assertExists(f)
self._CheckMarker(artifact.marker_name, artifact.installed_files)
@cros_test_lib.pytestmark_network_test
def testImageUnzipWithExcludes(self) -> None:
"""Downloads and stages a zip file while excluding all large files."""
artifact = build_artifact.BundledArtifact(
build_artifact.IMAGE_FILE,
self.work_dir,
_VERSION,
exclude=["*.bin"],
)
artifact.Process(self.dl, False)
expected_installed_files = [
os.path.join(self.work_dir, filename)
for filename in _TEST_GOLO_ARCHIVE_IMAGE_ZIPFILE_CONTENT
]
self.assertEqual(expected_installed_files, artifact.installed_files)
self.assertNotExists(
os.path.join(self.work_dir, "chromiumos_test_image.bin")
)
self._CheckMarker(artifact.marker_name, artifact.installed_files)
@cros_test_lib.pytestmark_network_test
def testArtifactFactory(self) -> None:
"""Tests that BuildArtifact works for both named and file artifacts."""
name_artifact = "test_suites" # This file is in every real GS dir.
file_artifact = "metadata.json" # This file is in every real GS dir.
factory = build_artifact.ChromeOSArtifactFactory(
self.work_dir, [name_artifact], [file_artifact], _VERSION
)
artifacts = factory.RequiredArtifacts()
self.assertEqual(len(artifacts), 2)
expected_installed_files_0 = [
os.path.join(self.work_dir, filename)
for filename in (
[build_artifact.TEST_SUITES_FILE]
+ _TEST_GOLO_ARCHIVE_TEST_TARBALL_CONTENT
)
]
expected_installed_files_1 = [
os.path.join(self.work_dir, file_artifact)
]
artifacts[0].Process(self.dl, False)
artifacts[1].Process(self.dl, False)
self.assertEqual(
artifacts[0].installed_files, expected_installed_files_0
)
self.assertEqual(
artifacts[1].installed_files, expected_installed_files_1
)
# Test suites directory exists.
self.assertExists(
os.path.join(self.work_dir, "autotest", "test_suites")
)
# File artifact was staged.
self.assertExists(os.path.join(self.work_dir, file_artifact))
self._CheckMarker(
artifacts[0].marker_name, artifacts[0].installed_files
)
self._CheckMarker(
artifacts[1].marker_name, artifacts[1].installed_files
)
def testProcessBuildArtifactWithException(self) -> None:
"""Test processing a non-existing artifact from GSUtil."""
gs_mock = self.StartPatcher(gs_unittest.GSContextMock())
gs_mock.SetDefaultCmdResult()
artifact = build_artifact.Artifact(
build_artifact.TEST_SUITES_FILE, self.work_dir, _VERSION
)
with self.assertRaises(build_artifact.ArtifactDownloadError) as cm:
dl = downloader.GoogleStorageDownloader(
self.work_dir,
_TEST_NON_EXISTING_GOLO_ARCHIVE,
_TEST_NON_EXISTING_GOLO_BUILD_ID,
)
artifact.Process(dl, False)
saved_exception = artifact.GetException()
# saved_exception has traceback info - strip it.
self.assertEqual(
# TODO(b/236161656): Fix.
# pylint: disable=used-before-assignment,use-maxsplit-arg
str(cm.exception),
str(saved_exception).split("\n")[0],
)
@cros_test_lib.pytestmark_network_test
def testArtifactStaged(self) -> None:
"""Tests the artifact staging verification logic."""
artifact = build_artifact.BundledArtifact(
build_artifact.TEST_SUITES_FILE, self.work_dir, _VERSION
)
expected_installed_files = [
os.path.join(self.work_dir, filename)
for filename in (
[build_artifact.TEST_SUITES_FILE]
+ _TEST_GOLO_ARCHIVE_TEST_TARBALL_CONTENT
)
]
artifact.Process(self.dl, False)
# Check that it works when all files are there.
self.assertTrue(artifact.ArtifactStaged())
# Remove an arbitrary file among the ones staged, ensure the check fails
# and that the marker files is removed.
os.remove(random.choice(expected_installed_files))
self.assertExists(os.path.join(self.work_dir, artifact.marker_name))
self.assertFalse(artifact.ArtifactStaged())
self.assertNotExists(os.path.join(self.work_dir, artifact.marker_name))
@cros_test_lib.pytestmark_network_test
def testStagedFiles(self) -> None:
"""Tests getting the staged files."""
files_to_extract = ["config.txt", "boot_images/vmlinuz"]
artifact = build_artifact.BundledArtifact(
build_artifact.IMAGE_FILE,
self.work_dir,
_VERSION,
files_to_extract=files_to_extract,
)
expected_extracted_files = [
os.path.join(self.work_dir, filename)
for filename in files_to_extract
]
artifact.Process(self.dl, False)
self.assertTrue(artifact.ArtifactStaged())
self.assertEqual(artifact.StagedFiles(), expected_extracted_files)