blob: 29d23a0d6e713f69d1e870f82728296b269f3754 [file] [log] [blame]
# Copyright 2019 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 trigger_gsc_signing.py."""
import json
import logging
from unittest import mock
from chromite.api.gen.chromiumos import common_pb2
from chromite.api.gen.chromiumos import sign_image_pb2
from chromite.lib import cros_test_lib
from chromite.lib import gs
from chromite.scripts import trigger_gsc_signing as trigger
# pylint: disable=protected-access
@mock.patch.object(gs.GSContext, "Exists", lambda x, y: True)
class TestLaunchOne(cros_test_lib.RunCommandTempDirTestCase):
"""Tests for the LaunchOne function."""
def setUp(self) -> None:
self.log_info = self.PatchObject(logging, "info")
self.properties = {"keyset": "test-keyest"}
self.json_prop = json.dumps(self.properties)
def testDryRunOnlyLogs(self) -> None:
"""Test that dryrun=True results in only a log message."""
trigger.LaunchOne(True, "chromeos/packaging/test", self.properties)
self.assertEqual(0, self.rc.call_count)
self.log_info.assert_called_once()
def testCallsRun(self) -> None:
"""Test that dryrun=False calls run()."""
trigger.LaunchOne(False, "chromeos/packaging/test", self.properties)
self.log_info.assert_not_called()
self.assertEqual(
[
mock.call(
[
"bb",
"add",
"-p",
"@/dev/stdin",
"chromeos/packaging/test",
],
input=self.json_prop,
log_output=True,
)
],
self.rc.call_args_list,
)
@mock.patch.object(gs.GSContext, "Exists", lambda x, y: True)
class TestMain(cros_test_lib.RunCommandTempDirTestCase):
"""Tests for the main function."""
def setUp(self) -> None:
self.log_error = self.PatchObject(logging, "error")
def testMinimal(self) -> None:
"""Test minimal instructions."""
launch = self.PatchObject(trigger, "LaunchOne")
args = ["--archive", "gs://test/file.bin", "--keyset", "test-keyset"]
self.assertEqual(0, trigger.main(args))
launch.assert_called_once_with(
False,
trigger.GSC_PRODUCTION_JOB,
{
"archive": "gs://test/file.bin",
"build_target": {
"name": "unknown",
},
"channel": common_pb2.CHANNEL_UNSPECIFIED,
"gsc_instructions": {
"target": sign_image_pb2.GscInstructions.PREPVT,
},
"image_type": common_pb2.IMAGE_TYPE_GSC_FIRMWARE,
"keyset": "test-keyset",
"signer_type": sign_image_pb2.SIGNER_PRODUCTION,
},
)
def testPropertiesCorrect(self) -> None:
"""Test minimal instructions."""
launch = self.PatchObject(trigger, "LaunchOne")
archive = "gs://test/file.bin"
keyset = "keyset"
channel = "canary"
build_target = "board"
target = "prepvt"
signer = "production"
image = "image_type_gsc_firmware"
args = [
"--archive",
archive,
"--keyset",
keyset,
"--channel",
channel,
"--build-target",
build_target,
"--target",
target,
"--signer-type",
signer,
]
self.assertEqual(0, trigger.main(args))
launch.assert_called_once_with(
False,
trigger.GSC_PRODUCTION_JOB,
{
"archive": archive,
"build_target": {
"name": build_target,
},
"channel": trigger._channels[channel],
"gsc_instructions": {
"target": trigger._target_types[target],
},
"image_type": trigger._image_types[image],
"keyset": keyset,
"signer_type": trigger._signer_types[signer],
},
)
def testStaging(self) -> None:
"""Test --staging works."""
launch = self.PatchObject(trigger, "LaunchOne")
args = [
"--archive",
"gs://test/file.bin",
"--keyset",
"test-keyset",
"--staging",
]
self.assertEqual(0, trigger.main(args))
launch.assert_called_once_with(
False,
trigger.GSC_STAGING_JOB,
{
"archive": "gs://test/file.bin",
"build_target": {
"name": "unknown",
},
"channel": common_pb2.CHANNEL_UNSPECIFIED,
"gsc_instructions": {
"target": sign_image_pb2.GscInstructions.PREPVT,
},
"image_type": common_pb2.IMAGE_TYPE_GSC_FIRMWARE,
"keyset": "test-keyset",
"signer_type": sign_image_pb2.SIGNER_PRODUCTION,
},
)
def testDryRun(self) -> None:
"""Test --dry-run works."""
launch = self.PatchObject(trigger, "LaunchOne")
args = [
"--archive",
"gs://test/file.bin",
"--keyset",
"test-keyset",
"--dry-run",
]
self.assertEqual(0, trigger.main(args))
launch.assert_called_once_with(
True,
trigger.GSC_PRODUCTION_JOB,
{
"archive": "gs://test/file.bin",
"build_target": {
"name": "unknown",
},
"channel": common_pb2.CHANNEL_UNSPECIFIED,
"gsc_instructions": {
"target": sign_image_pb2.GscInstructions.PREPVT,
},
"image_type": common_pb2.IMAGE_TYPE_GSC_FIRMWARE,
"keyset": "test-keyset",
"signer_type": sign_image_pb2.SIGNER_PRODUCTION,
},
)
def testNightlyCorrect(self) -> None:
"""Test --target nightly works with ti50-accessor-y-ro-premp."""
launch = self.PatchObject(trigger, "LaunchOne")
target = "nightly"
keyset = "ti50-accessory-nodelocked-ro-premp"
archive = "gs://test/file.bin"
args = [
"--archive",
archive,
"--keyset",
keyset,
"--target",
target,
]
self.assertEqual(0, trigger.main(args))
launch.assert_called_once_with(
False,
trigger.GSC_PRODUCTION_JOB,
{
"archive": archive,
"build_target": {
"name": "unknown",
},
"channel": common_pb2.CHANNEL_UNSPECIFIED,
"gsc_instructions": {
"target": sign_image_pb2.GscInstructions.NIGHTLY,
},
"image_type": common_pb2.IMAGE_TYPE_GSC_FIRMWARE,
"keyset": keyset,
"signer_type": sign_image_pb2.SIGNER_PRODUCTION,
},
)
def testNightlyRequiresTi50AccessoryNodelockedRoPremp(self) -> None:
"""Test --target nightly requires ti50-accessory-nodelocked-ro-premp."""
launch = self.PatchObject(trigger, "LaunchOne")
args = [
"--archive",
"gs://test/file.bin",
"--keyset",
"test-keyset",
"--target",
"nightly",
]
self.assertEqual(1, trigger.main(args))
launch.assert_not_called()
self.assertEqual(1, self.log_error.call_count)
def testNodeLockedCatchesBadDeviceId(self) -> None:
"""Test --target node_locked catches bad --device-id."""
launch = self.PatchObject(trigger, "LaunchOne")
args = [
"--archive",
"gs://test/file.bin",
"--keyset",
"test-keyset",
"--target",
"node_locked",
"--device-id",
"12345678-9ABCDEFG",
"--dev01",
"-1",
"0x1234",
]
self.assertEqual(1, trigger.main(args))
launch.assert_not_called()
self.assertEqual(1, self.log_error.call_count)
def testNodeLockedRequiresDeviceId(self) -> None:
"""Test --target node_locked requires --device-id."""
launch = self.PatchObject(trigger, "LaunchOne")
args = [
"--archive",
"gs://test/file.bin",
"--keyset",
"test-keyset",
"--target",
"node_locked",
]
self.assertEqual(1, trigger.main(args))
launch.assert_not_called()
self.assertEqual(1, self.log_error.call_count)
def testDeviceIdRequiresNodeLocked(self) -> None:
"""Test --device_id is rejected if not node_locked."""
launch = self.PatchObject(trigger, "LaunchOne")
args = [
"--archive",
"gs://test/file.bin",
"--keyset",
"test-keyset",
"--target",
"general_release",
"--dev01",
"1",
"0x1234",
]
self.assertEqual(1, trigger.main(args))
launch.assert_not_called()
self.assertEqual(1, self.log_error.call_count)
def testNodeLockedLaunchesMultiple(self) -> None:
"""Test --target node_locked launches multiple jobs."""
# Do not mock LaunchOne, so that we can grab the input= passed to run().
args = [
"--archive",
"gs://test/file.bin",
"--keyset",
"test-keyset",
"--target",
"node_locked",
"--dev01",
"1",
"0x1234",
"--dev01",
"2",
"33",
]
self.assertEqual(0, trigger.main(args))
self.log_error.assert_not_called()
expected_properties = [
{
"archive": "gs://test/file.bin",
"build_target": {
"name": "unknown",
},
"channel": 0,
"gsc_instructions": {
"target": trigger._target_types["node_locked"],
"device_id": "00000001-00001234",
},
"signer_type": sign_image_pb2.SIGNER_PRODUCTION,
"image_type": common_pb2.IMAGE_TYPE_GSC_FIRMWARE,
"keyset": "test-keyset",
},
{
"archive": "gs://test/file.bin",
"build_target": {
"name": "unknown",
},
"channel": 0,
"gsc_instructions": {
"target": trigger._target_types["node_locked"],
"device_id": "00000002-00000021",
},
"signer_type": sign_image_pb2.SIGNER_PRODUCTION,
"image_type": common_pb2.IMAGE_TYPE_GSC_FIRMWARE,
"keyset": "test-keyset",
},
]
# Check the calls in two parts, since we need to convert the json string
# back to a dict.
self.assertEqual(
self.rc.call_args_list,
[
mock.call(
[
"bb",
"add",
"-p",
"@/dev/stdin",
trigger.GSC_PRODUCTION_JOB,
],
log_output=True,
input=mock.ANY,
)
for _ in expected_properties
],
)
self.assertEqual(
expected_properties,
[json.loads(x[1]["input"]) for x in self.rc.call_args_list],
)