Make ResourceType a required field in EM configs

In follow up cl/758720742 we will use ResourceType to determine subfru status instead of the IsSubFru ProbeV2 property. To support this change, we should enforce explicit definition of ResourceType in all EM configs. Previously, unconfigured ResourceType would lead to default behavior of treating the resource as a RESOURCE_TYPE_BOARD, to have better defined behavior, we now will fail tlBMC store creation if ResourceType is not defined or an unrecognized type.

Update all existing unit tests to now have ResourceType defined, add cases for errors

#tlbmc

PiperOrigin-RevId: 760657431
Change-Id: Ia316451a4971e87d0d50b6363d2d05f1a2623581
diff --git a/tlbmc/configs/entity_config_json_impl.cc b/tlbmc/configs/entity_config_json_impl.cc
index 2b5f7ed..50c5fff 100644
--- a/tlbmc/configs/entity_config_json_impl.cc
+++ b/tlbmc/configs/entity_config_json_impl.cc
@@ -242,26 +242,22 @@
   return chassis_type;
 }
 
-void ParseResourceType(const nlohmann::json& config, Fru& fru_object) {
+absl::StatusOr<ResourceType> ParseResourceType(const nlohmann::json& config) {
   const std::string* resource_type_str =
       GetValueAsString(config, kResourceTypeKeyword);
   if (resource_type_str == nullptr) {
-    LOG(INFO) << "No resource type found for config: " << config.dump();
-    return;
+    return absl::InvalidArgumentError(absl::StrCat(
+        "Invalid config: No resource type found for config ", config.dump()));
   }
 
   ResourceType resource_type;
   if (!ResourceType_Parse(*resource_type_str, &resource_type)) {
-    LOG(WARNING) << "Invalid resource type found for config: "
-                 << *resource_type_str;
-    return;
+    return absl::InvalidArgumentError(
+        absl::StrCat("Invalid config: Invalid resource type found for config: ",
+                     *resource_type_str));
   }
 
-  if (resource_type == RESOURCE_TYPE_BOARD) {
-    fru_object.mutable_attributes()->set_chassis_type(ParseChassisType(config));
-  }
-
-  fru_object.mutable_attributes()->set_resource_type(resource_type);
+  return resource_type;
 }
 
 void ParsePartLocationType(const nlohmann::json& config,
@@ -941,9 +937,28 @@
 
       const std::string fru_key = config_data.fru_keys[i].ToString();
 
-      ParseResourceType(
-          config_data.config,
-          mutable_data.fru_table.mutable_key_to_fru()->at(fru_key));
+      absl::StatusOr<ResourceType> resource_type =
+          ParseResourceType(config_data.config);
+
+      if (!resource_type.ok()) {
+        mutable_data.parsed_status = resource_type.status();
+        return EntityConfigJsonImplData{
+            .immutable_data = std::move(immutable_data),
+            .mutable_data = std::move(mutable_data),
+            .max_updates_to_mutable_data = ad_hoc_fru_count};
+      }
+
+      // Get the FRU object from the fru_key. This is used to update the Fru
+      // object fields with Fru information from config.
+      // Key is not expected to be invalid.
+      Fru& fru = mutable_data.fru_table.mutable_key_to_fru()->at(fru_key);
+
+      fru.mutable_attributes()->set_resource_type(*resource_type);
+
+      if (*resource_type == RESOURCE_TYPE_BOARD) {
+        fru.mutable_attributes()->set_chassis_type(
+            ParseChassisType(config_data.config));
+      }
 
       ParsePartLocationType(config_data.config, topology_config_node);
       ParseRootChassisLocationCode(config_data.config, topology_config_node);
@@ -1101,8 +1116,7 @@
       }
 
       absl::Status parse_asset_config_status = ParseAssetConfig(
-          config_data.config,
-          mutable_data.fru_table.mutable_key_to_fru()->at(fru_key));
+          config_data.config, fru);
       if (!parse_asset_config_status.ok()) {
         mutable_data.parsed_status = parse_asset_config_status;
         return EntityConfigJsonImplData{