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.py b/api/controller/test.py
index f9fa8ee..b3d5c90 100644
--- a/api/controller/test.py
+++ b/api/controller/test.py
@@ -26,7 +26,7 @@
 from chromite.service import test
 
 
-def DebugInfoTest(input_proto, _output_proto):
+def DebugInfoTest(input_proto, _output_proto, config):
   """Run the debug info tests."""
   sysroot_path = input_proto.sysroot.path
   target_name = input_proto.sysroot.build_target.name
@@ -43,6 +43,9 @@
   if not sysroot.Exists():
     cros_build_lib.Die('The provided sysroot does not exist.')
 
+  if config.validate_only:
+    return controller.RETURN_CODE_VALID_INPUT
+
   if test.DebugInfoTest(sysroot_path):
     return controller.RETURN_CODE_SUCCESS
   else:
@@ -50,7 +53,9 @@
 
 
 @validate.require('build_target.name', 'result_path')
-def BuildTargetUnitTest(input_proto, output_proto):
+@validate.exists('result_path')
+@validate.validation_complete
+def BuildTargetUnitTest(input_proto, output_proto, _config):
   """Run a build target's ebuild unit tests."""
   # Required args.
   board = input_proto.build_target.name
@@ -90,7 +95,8 @@
     output_proto.tarball_path = tarball
 
 
-def ChromiteUnitTest(_input_proto, _output_proto):
+@validate.validation_complete
+def ChromiteUnitTest(_input_proto, _output_proto, _config):
   """Run the chromite unit tests."""
   cmd = [os.path.join(constants.CHROMITE_DIR, 'scripts', 'run_tests')]
   result = cros_build_lib.RunCommand(cmd, error_code_ok=True)
@@ -102,14 +108,13 @@
 
 @validate.require('build_target.name', 'vm_path.path', 'test_harness',
                   'vm_tests')
-def VmTest(input_proto, _output_proto):
+@validate.validation_complete
+def VmTest(input_proto, _output_proto, _config):
   """Run VM tests."""
   build_target_name = input_proto.build_target.name
   vm_path = input_proto.vm_path.path
 
   test_harness = input_proto.test_harness
-  if test_harness == test_pb2.VmTestRequest.UNSPECIFIED:
-    cros_build_lib.Die('test_harness is required')
 
   vm_tests = input_proto.vm_tests
 
@@ -134,7 +139,9 @@
     cros_build_lib.RunCommand(cmd, kill_timeout=10 * 60)
 
 
-def MoblabVmTest(input_proto, _output_proto):
+@validate.require('image_payload.path.path', 'cache_payloads')
+@validate.validation_complete
+def MoblabVmTest(input_proto, _output_proto, _config):
   """Run Moblab VM tests."""
   chroot = controller_util.ParseChroot(input_proto.chroot)
   image_payload_dir = input_proto.image_payload.path.path