ImageService/Create: Add factory support.

Add support for building a factory image to ImageService/Create.
Also refactored the code to put more responsibility in the service
layer rather than the controller layer, especially WRT creating
the image paths.
Created a class to simplify the parsed image type result.
Reworked the BuildResult to help track status.

BUG=b:194730793
TEST=./run_tests, cq

Change-Id: Ic541c47660552c86739c64d5a479aa7744a7f164
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/chromite/+/3059809
Tested-by: Alex Klein <saklein@chromium.org>
Commit-Queue: George Engelbrecht <engeg@google.com>
Reviewed-by: George Engelbrecht <engeg@google.com>
Reviewed-by: Sergey Frolov <sfrolov@google.com>
diff --git a/api/controller/image_unittest.py b/api/controller/image_unittest.py
index 25d4b0f..2413108 100644
--- a/api/controller/image_unittest.py
+++ b/api/controller/image_unittest.py
@@ -82,24 +82,26 @@
     request = self._GetRequest(board='board')
 
     # Failed result to avoid the success handling logic.
-    result = image_service.BuildResult(1, [])
+    result = image_service.BuildResult([constants.IMAGE_TYPE_BASE])
+    result.return_code = 1
     build_patch = self.PatchObject(image_service, 'Build', return_value=result)
 
     image_controller.Create(request, self.response, self.api_config)
-    build_patch.assert_called_with(
-        images=[constants.IMAGE_TYPE_BASE], board='board', config=mock.ANY)
+    build_patch.assert_any_call(
+        'board', [constants.IMAGE_TYPE_BASE], config=mock.ANY)
 
   def testSingleTypeSpecified(self):
     """Test it's properly using a specified type."""
     request = self._GetRequest(board='board', types=[common_pb2.IMAGE_TYPE_DEV])
 
     # Failed result to avoid the success handling logic.
-    result = image_service.BuildResult(1, [])
+    result = image_service.BuildResult([constants.IMAGE_TYPE_DEV])
+    result.return_code = 1
     build_patch = self.PatchObject(image_service, 'Build', return_value=result)
 
     image_controller.Create(request, self.response, self.api_config)
-    build_patch.assert_called_with(
-        images=[constants.IMAGE_TYPE_DEV], board='board', config=mock.ANY)
+    build_patch.assert_any_call(
+        'board', [constants.IMAGE_TYPE_DEV], config=mock.ANY)
 
   def testMultipleAndImpliedTypes(self):
     """Test multiple types and implied type handling."""
@@ -110,12 +112,12 @@
     request = self._GetRequest(board='board', types=types)
 
     # Failed result to avoid the success handling logic.
-    result = image_service.BuildResult(1, [])
+    result = image_service.BuildResult(expected_images)
+    result.return_code = 1
     build_patch = self.PatchObject(image_service, 'Build', return_value=result)
 
     image_controller.Create(request, self.response, self.api_config)
-    build_patch.assert_called_with(
-        images=expected_images, board='board', config=mock.ANY)
+    build_patch.assert_any_call('board', expected_images, config=mock.ANY)
 
   def testRecoveryImpliedTypes(self):
     """Test implied type handling of recovery images."""
@@ -125,16 +127,19 @@
     request = self._GetRequest(board='board', types=types)
 
     # Failed result to avoid the success handling logic.
-    result = image_service.BuildResult(1, [])
+    result = image_service.BuildResult([])
+    result.return_code = 1
     build_patch = self.PatchObject(image_service, 'Build', return_value=result)
 
     image_controller.Create(request, self.response, self.api_config)
-    build_patch.assert_called_with(
-        images=[constants.IMAGE_TYPE_BASE], board='board', config=mock.ANY)
+    build_patch.assert_any_call(
+        'board', [constants.IMAGE_TYPE_BASE], config=mock.ANY)
 
   def testFailedPackageHandling(self):
     """Test failed packages are populated correctly."""
-    result = image_service.BuildResult(1, ['foo/bar', 'cat/pkg'])
+    result = image_service.BuildResult([])
+    result.return_code = 1
+    result.failed_packages = ['foo/bar', 'cat/pkg']
     expected_packages = [('foo', 'bar'), ('cat', 'pkg')]
     self.PatchObject(image_service, 'Build', return_value=result)
 
@@ -148,7 +153,8 @@
 
   def testNoPackagesFailureHandling(self):
     """Test failed packages are populated correctly."""
-    result = image_service.BuildResult(1, [])
+    result = image_service.BuildResult([])
+    result.return_code = 1
     self.PatchObject(image_service, 'Build', return_value=result)
 
     input_proto = image_pb2.CreateImageRequest()