Build API: Implement validate_only calls.
Add validate-only support to all existing endpoints and
tests to enforce the setting is respected.
Add is_in validator to help transition some endpoints
to decorator-only validation.
Some cleanup and standardization in the controller tests.
BUG=chromium:987263
TEST=run_tests
Cq-Depend: chromium:1726252
Change-Id: I108dfc1a221847eae47a18f2f60e12d2575c9ea8
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/chromite/+/1726253
Reviewed-by: David Burger <dburger@chromium.org>
Commit-Queue: Alex Klein <saklein@chromium.org>
Tested-by: Alex Klein <saklein@chromium.org>
diff --git a/api/controller/test_unittest.py b/api/controller/test_unittest.py
index f73e1c2..49f3615 100644
--- a/api/controller/test_unittest.py
+++ b/api/controller/test_unittest.py
@@ -10,6 +10,7 @@
import contextlib
import mock
+from chromite.api import api_config
from chromite.api import controller
from chromite.api.controller import test as test_controller
from chromite.api.gen.chromiumos import common_pb2
@@ -24,7 +25,8 @@
from chromite.service import test as test_service
-class BuildTargetUnitTestTest(cros_test_lib.MockTempDirTestCase):
+class BuildTargetUnitTestTest(cros_test_lib.MockTempDirTestCase,
+ api_config.ApiConfigMixin):
"""Tests for the UnitTest function."""
def _GetInput(self, board=None, result_path=None, chroot_path=None,
@@ -46,19 +48,30 @@
"""Helper to get an empty output message instance."""
return test_pb2.BuildTargetUnitTestResponse()
+ def testValidateOnly(self):
+ """Sanity check that a validate only call does not execute any logic."""
+ patch = self.PatchObject(test_service, 'BuildTargetUnitTest')
+
+ input_msg = self._GetInput(board='board', result_path=self.tempdir)
+ test_controller.BuildTargetUnitTest(input_msg, self._GetOutput(),
+ self.validate_only_config)
+ patch.assert_not_called()
+
def testNoArgumentFails(self):
"""Test no arguments fails."""
input_msg = self._GetInput()
output_msg = self._GetOutput()
with self.assertRaises(cros_build_lib.DieSystemExit):
- test_controller.BuildTargetUnitTest(input_msg, output_msg)
+ test_controller.BuildTargetUnitTest(input_msg, output_msg,
+ self.api_config)
def testNoBuildTargetFails(self):
"""Test missing build target name fails."""
input_msg = self._GetInput(result_path=self.tempdir)
output_msg = self._GetOutput()
with self.assertRaises(cros_build_lib.DieSystemExit):
- test_controller.BuildTargetUnitTest(input_msg, output_msg)
+ test_controller.BuildTargetUnitTest(input_msg, output_msg,
+ self.api_config)
def testNoResultPathFails(self):
"""Test missing result path fails."""
@@ -66,7 +79,8 @@
input_msg = self._GetInput(board='board')
output_msg = self._GetOutput()
with self.assertRaises(cros_build_lib.DieSystemExit):
- test_controller.BuildTargetUnitTest(input_msg, output_msg)
+ test_controller.BuildTargetUnitTest(input_msg, output_msg,
+ self.api_config)
def testPackageBuildFailure(self):
"""Test handling of raised BuildPackageFailure."""
@@ -83,7 +97,8 @@
input_msg = self._GetInput(board='board', result_path=self.tempdir)
output_msg = self._GetOutput()
- rc = test_controller.BuildTargetUnitTest(input_msg, output_msg)
+ rc = test_controller.BuildTargetUnitTest(input_msg, output_msg,
+ self.api_config)
self.assertEqual(controller.RETURN_CODE_UNSUCCESSFUL_RESPONSE_AVAILABLE, rc)
self.assertTrue(output_msg.failed_packages)
@@ -106,13 +121,14 @@
empty_sysroot=True, blacklist=blacklist)
output_msg = self._GetOutput()
- rc = test_controller.BuildTargetUnitTest(input_msg, output_msg)
+ rc = test_controller.BuildTargetUnitTest(input_msg, output_msg,
+ self.api_config)
self.assertEqual(controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY, rc)
self.assertFalse(output_msg.failed_packages)
-class VmTestTest(cros_test_lib.MockTestCase):
+class VmTestTest(cros_test_lib.RunCommandTestCase, api_config.ApiConfigMixin):
"""Test the VmTest endpoint."""
def _GetInput(self, **kwargs):
@@ -123,21 +139,21 @@
test_harness=test_pb2.VmTestRequest.TAST,
vm_tests=[test_pb2.VmTestRequest.VmTest(pattern='suite')],
ssh_options=test_pb2.VmTestRequest.SshOptions(
- port=1234, private_key_path={'path':'/path/to/id_rsa',
+ port=1234, private_key_path={'path': '/path/to/id_rsa',
'location': common_pb2.Path.INSIDE}),
)
values.update(kwargs)
return test_pb2.VmTestRequest(**values)
- def setUp(self):
- self.rc_mock = cros_test_lib.RunCommandMock()
- self.rc_mock.SetDefaultCmdResult()
- self.StartPatcher(self.rc_mock)
+ def testValidateOnly(self):
+ """Sanity check that a validate only call does not execute any logic."""
+ test_controller.VmTest(self._GetInput(), None, self.validate_only_config)
+ self.assertEqual(0, self.rc.call_count)
def testTastAllOptions(self):
"""Test VmTest for Tast with all options set."""
- test_controller.VmTest(self._GetInput(), None)
- self.rc_mock.assertCommandContains([
+ test_controller.VmTest(self._GetInput(), None, self.api_config)
+ self.assertCommandContains([
'cros_run_test', '--debug', '--no-display', '--copy-on-write',
'--board', 'target',
'--image-path', '/path/to/image.bin',
@@ -149,8 +165,8 @@
def testAutotestAllOptions(self):
"""Test VmTest for Autotest with all options set."""
input_proto = self._GetInput(test_harness=test_pb2.VmTestRequest.AUTOTEST)
- test_controller.VmTest(input_proto, None)
- self.rc_mock.assertCommandContains([
+ test_controller.VmTest(input_proto, None, self.api_config)
+ self.assertCommandContains([
'cros_run_test', '--debug', '--no-display', '--copy-on-write',
'--board', 'target',
'--image-path', '/path/to/image.bin',
@@ -164,29 +180,29 @@
"""Test VmTest dies when build_target not set."""
input_proto = self._GetInput(build_target=None)
with self.assertRaises(cros_build_lib.DieSystemExit):
- test_controller.VmTest(input_proto, None)
+ test_controller.VmTest(input_proto, None, self.api_config)
def testMissingVmImage(self):
"""Test VmTest dies when vm_image not set."""
input_proto = self._GetInput(vm_path=None)
with self.assertRaises(cros_build_lib.DieSystemExit):
- test_controller.VmTest(input_proto, None)
+ test_controller.VmTest(input_proto, None, self.api_config)
def testMissingTestHarness(self):
"""Test VmTest dies when test_harness not specified."""
input_proto = self._GetInput(
test_harness=test_pb2.VmTestRequest.UNSPECIFIED)
with self.assertRaises(cros_build_lib.DieSystemExit):
- test_controller.VmTest(input_proto, None)
+ test_controller.VmTest(input_proto, None, self.api_config)
def testMissingVmTests(self):
"""Test VmTest dies when vm_tests not set."""
input_proto = self._GetInput(vm_tests=[])
with self.assertRaises(cros_build_lib.DieSystemExit):
- test_controller.VmTest(input_proto, None)
+ test_controller.VmTest(input_proto, None, self.api_config)
-class MoblabVmTestTest(cros_test_lib.MockTestCase):
+class MoblabVmTestTest(cros_test_lib.MockTestCase, api_config.ApiConfigMixin):
"""Test the MoblabVmTest endpoint."""
@staticmethod
@@ -230,8 +246,15 @@
mount = mock.MagicMock()
mount.Mount.return_value = [self.image_mount_dir]
yield mount
+
self.PatchObject(image_lib, 'LoopbackPartitions', MockLoopbackPartitions)
+ def testValidateOnly(self):
+ """Sanity check that a validate only call does not execute any logic."""
+ test_controller.MoblabVmTest(self._Input(), self._Output(),
+ self.validate_only_config)
+ self.mock_create_moblab_vms.assert_not_called()
+
def testImageContainsBuilder(self):
"""MoblabVmTest calls service with correct args."""
request = self._Input()
@@ -241,7 +264,7 @@
cros_build_lib, 'LoadKeyValueFile',
return_value={cros_set_lsb_release.LSB_KEY_BUILDER_PATH: self.builder})
- test_controller.MoblabVmTest(request, response)
+ test_controller.MoblabVmTest(request, response, self.api_config)
self.assertEqual(
self.mock_create_moblab_vms.call_args_list,
@@ -265,4 +288,4 @@
self.PatchObject(cros_build_lib, 'LoadKeyValueFile', return_value={})
with self.assertRaises(cros_build_lib.DieSystemExit):
- test_controller.MoblabVmTest(request, response)
+ test_controller.MoblabVmTest(request, response, self.api_config)