api: test & image: detect and handle artifact failures

BUG=b:255838545
TEST=run_tests

Change-Id: I9b63d2ac4c32c73b26eb971e974b0c20373eb0b9
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/chromite/+/4068814
Reviewed-by: Jack Neus <jackneus@google.com>
Commit-Queue: Josiah Hounyo <josiahh@google.com>
Tested-by: Josiah Hounyo <josiahh@google.com>
Reviewed-by: Chris Gerber <gerb@google.com>
diff --git a/api/controller/test.py b/api/controller/test.py
index 3431460..6b06f86 100644
--- a/api/controller/test.py
+++ b/api/controller/test.py
@@ -12,6 +12,7 @@
 import os
 import string
 import subprocess
+import traceback
 
 from chromite.third_party.google.protobuf import json_format
 
@@ -463,10 +464,34 @@
     for output_artifact in in_proto.output_artifacts:
         for artifact_type, func in artifact_types.items():
             if artifact_type in output_artifact.artifact_types:
-                if artifact_type == in_proto.ArtifactType.CODE_COVERAGE_GOLANG:
-                    paths = func(chroot, output_dir)
-                else:
-                    paths = func(chroot, sysroot_class, output_dir)
+                try:
+                    if (
+                        artifact_type
+                        == in_proto.ArtifactType.CODE_COVERAGE_GOLANG
+                    ):
+                        paths = func(chroot, output_dir)
+                    else:
+                        paths = func(chroot, sysroot_class, output_dir)
+                except Exception as e:
+                    generated.append(
+                        {
+                            "type": artifact_type,
+                            "failed": True,
+                            "failure_reason": str(e),
+                        }
+                    )
+                    artifact_name = (
+                        common_pb2.ArtifactsByService.Test.ArtifactType.Name(
+                            artifact_type
+                        )
+                    )
+                    logging.warning(
+                        "%s artifact generation failed with exception %s",
+                        artifact_name,
+                        e,
+                    )
+                    logging.warning("traceback:\n%s", traceback.format_exc())
+                    continue
                 if paths:
                     generated.append(
                         {