Add SignerTest to BuildAPI's ImageService.

BUG=chromium:990487
TEST=manual, run_tests

Change-Id: I17d999992ee306ec1ae2bbcebf5daca43dc1f068
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/chromite/+/1737143
Reviewed-by: Alex Klein <saklein@chromium.org>
Tested-by: Michael Mortensen <mmortensen@google.com>
Commit-Queue: Michael Mortensen <mmortensen@google.com>
diff --git a/api/controller/image.py b/api/controller/image.py
index 97b7e8a..9099e02 100644
--- a/api/controller/image.py
+++ b/api/controller/image.py
@@ -161,6 +161,25 @@
     new_image.build_target.name = board
 
 
+@validate.require('build_target.name')
+@validate.exists('image.path')
+def SignerTest(input_proto, output_proto):
+  """Run image tests.
+
+  Args:
+    input_proto (image_pb2.ImageTestRequest): The input message.
+    output_proto (image_pb2.ImageTestResult): The output message.
+  """
+  board = input_proto.build_target.name
+  image_path = input_proto.image.path
+
+  result = image_lib.SecurityTest(board=board, image=image_path)
+  output_proto.success = result
+  if result:
+    return controller.RETURN_CODE_SUCCESS
+  else:
+    return controller.RETURN_CODE_COMPLETED_UNSUCCESSFULLY
+
 @validate.require('build_target.name', 'result.directory')
 @validate.exists('image.path')
 def Test(input_proto, output_proto):
diff --git a/api/controller/image_unittest.py b/api/controller/image_unittest.py
index a52ebb7..2b4d9c3 100644
--- a/api/controller/image_unittest.py
+++ b/api/controller/image_unittest.py
@@ -17,6 +17,7 @@
 from chromite.lib import constants
 from chromite.lib import cros_build_lib
 from chromite.lib import cros_test_lib
+from chromite.lib import image_lib
 from chromite.lib import osutils
 from chromite.service import image as image_service
 
@@ -122,6 +123,74 @@
     self.assertFalse(output_proto.failed_packages)
 
 
+class ImageSignerTestTest(cros_test_lib.MockTempDirTestCase):
+  """Image signer test tests."""
+
+  def setUp(self):
+    self.image_path = os.path.join(self.tempdir, 'image.bin')
+    self.board = 'board'
+    self.result_directory = os.path.join(self.tempdir, 'results')
+
+    osutils.SafeMakedirs(self.result_directory)
+    osutils.Touch(self.image_path)
+
+  def testSignerTestArgumentValidation(self):
+    """Test function argument validation tests."""
+    self.PatchObject(image_lib, 'SecurityTest', return_value=True)
+    input_proto = image_pb2.TestImageRequest()
+    output_proto = image_pb2.TestImageResult()
+
+    # Nothing provided.
+    with self.assertRaises(cros_build_lib.DieSystemExit):
+      image_controller.Test(input_proto, output_proto)
+
+    # Just one argument.
+    input_proto.build_target.name = self.board
+    with self.assertRaises(cros_build_lib.DieSystemExit):
+      image_controller.Test(input_proto, output_proto)
+
+    # Two arguments provided.
+    input_proto.result.directory = self.result_directory
+    with self.assertRaises(cros_build_lib.DieSystemExit):
+      image_controller.Test(input_proto, output_proto)
+
+    # Invalid image path.
+    input_proto.image.path = '/invalid/image/path'
+    with self.assertRaises(cros_build_lib.DieSystemExit):
+      image_controller.Test(input_proto, output_proto)
+
+    # All valid arguments.
+    input_proto.image.path = self.image_path
+    image_controller.Test(input_proto, output_proto)
+
+  def testSignerTestOutputHandling(self):
+    """Test function output tests."""
+    input_proto = image_pb2.TestImageRequest()
+    input_proto.image.path = self.image_path
+    input_proto.build_target.name = self.board
+    input_proto.result.directory = self.result_directory
+    output_proto = image_pb2.TestImageResult()
+
+    self.PatchObject(image_lib, 'SecurityTest', return_value=True)
+    image_controller.SignerTest(input_proto, output_proto)
+    self.assertTrue(output_proto.success)
+
+    self.PatchObject(image_lib, 'SecurityTest', return_value=False)
+    image_controller.SignerTest(input_proto, output_proto)
+    self.assertFalse(output_proto.success)
+
+  def testSignerTestWithoutMocks(self):
+    """Test function with fake image to sign."""
+    input_proto = image_pb2.TestImageRequest()
+    input_proto.image.path = self.image_path
+    input_proto.build_target.name = self.board
+    input_proto.result.directory = self.result_directory
+    output_proto = image_pb2.TestImageResult()
+
+    image_controller.SignerTest(input_proto, output_proto)
+    self.assertTrue(output_proto.success)
+
+
 class ImageTestTest(cros_test_lib.MockTempDirTestCase):
   """Image test tests."""