dsp: Add FD side firmware_update encode/decode

This implements FD counterparts for firmware update (type 5)
encoding/decoding.

In tests after encoding a message, a subsequent decode is performed and
the outputs are compared. This tests the FD portion of the message
decoding.

Change-Id: I5454acee19588b0679a9b0218588fc4c0a66b01d
Signed-off-by: Matt Johnston <matt@codeconstruct.com.au>
diff --git a/tests/dsp/firmware_update.cpp b/tests/dsp/firmware_update.cpp
index 6a2ec68..23a5d4f 100644
--- a/tests/dsp/firmware_update.cpp
+++ b/tests/dsp/firmware_update.cpp
@@ -24,6 +24,24 @@
 
 constexpr auto hdrSize = sizeof(pldm_msg_hdr);
 
+#ifdef LIBPLDM_API_TESTING
+
+static const uint8_t FIXED_INSTANCE_ID = 31;
+
+/* data is a pointer to pldm message response header */
+static void check_response(const void* data, uint8_t command)
+{
+    auto enc = static_cast<const pldm_msg*>(data);
+    EXPECT_EQ(enc->hdr.request, PLDM_RESPONSE);
+    EXPECT_EQ(enc->hdr.type, PLDM_FWUP);
+    EXPECT_EQ(enc->hdr.command, command);
+    EXPECT_EQ(enc->hdr.reserved, 0);
+    EXPECT_EQ(enc->hdr.datagram, 0);
+    EXPECT_EQ(enc->hdr.header_ver, 0);
+    EXPECT_EQ(enc->hdr.instance_id, FIXED_INSTANCE_ID);
+}
+#endif
+
 TEST(DecodePackageHeaderInfo, goodPath)
 {
     // Package header identifier for Version 1.0.x
@@ -858,6 +876,61 @@
                          responseMsg.end()));
 }
 
+#ifdef LIBPLDM_API_TESTING
+TEST(QueryDeviceIdentifiers, goodPathEncodeResponse)
+{
+    int rc;
+    PLDM_MSG_DEFINE_P(enc, 1000);
+    size_t enc_payload_len = 1000;
+    pldm_descriptor check_desc[] = {
+        {
+            .descriptor_type = PLDM_FWUP_IANA_ENTERPRISE_ID,
+            .descriptor_length = 4,
+            .descriptor_data = "a123",
+        },
+        {
+            .descriptor_type = PLDM_FWUP_VENDOR_DEFINED,
+            .descriptor_length = 3,
+            .descriptor_data = "987",
+        },
+    };
+    rc = encode_query_device_identifiers_resp(FIXED_INSTANCE_ID, 2, check_desc,
+                                              enc, &enc_payload_len);
+    EXPECT_EQ(rc, 0);
+    EXPECT_THAT(std::span<uint8_t>(enc_buf + hdrSize, enc_payload_len),
+                ElementsAreArray<uint8_t>({
+                    // completion code
+                    0x00,
+                    // device identifiers length = 15
+                    0x0f,
+                    0x00,
+                    0x00,
+                    0x00,
+                    // descriptor count
+                    0x02,
+                    // desc 0
+                    0x01,
+                    0x00,
+                    0x04,
+                    0x00,
+                    0x61,
+                    0x31,
+                    0x32,
+                    0x33,
+                    // desc 1
+                    0xff,
+                    0xff,
+                    0x03,
+                    0x00,
+                    0x39,
+                    0x38,
+                    0x37,
+                }));
+
+    check_response(enc, PLDM_QUERY_DEVICE_IDENTIFIERS);
+}
+#endif
+
 TEST(GetFirmwareParameters, goodPathEncodeRequest)
 {
     std::array<uint8_t, sizeof(pldm_msg_hdr)> requestMsg{};
@@ -1221,6 +1294,7 @@
     constexpr uint16_t compClassification = 0x0a0b;
     // Random value for component classification
     constexpr uint16_t compIdentifier = 0x0c0d;
+    constexpr uint16_t compClassificationIndex = 0xf;
     // Random value for component classification
     constexpr uint32_t timestamp = 0x12345678;
     // Random value for component activation methods
@@ -1243,7 +1317,7 @@
 
     inEntry->comp_classification = htole16(compClassification);
     inEntry->comp_identifier = htole16(compIdentifier);
-    inEntry->comp_classification_index = 0x0f;
+    inEntry->comp_classification_index = compClassificationIndex;
     inEntry->active_comp_comparison_stamp = htole32(timestamp);
     inEntry->active_comp_ver_str_type = 1;
     inEntry->active_comp_ver_str_len = activeCompVerStrLen;
@@ -1305,6 +1379,48 @@
     EXPECT_EQ(0, memcmp(outPendingCompVerStr.ptr,
                         entry.data() + pendingCompVerStrPos,
                         outPendingCompVerStr.length));
+
+#ifdef LIBPLDM_API_TESTING
+    /* Check the roundtrip matches */
+    std::vector<uint8_t> enc_data(1000);
+    size_t enc_payload_len = enc_data.size();
+    struct pldm_component_parameter_entry_full entryFull = {
+        .comp_classification = compClassification,
+        .comp_identifier = compIdentifier,
+        .comp_classification_index = compClassificationIndex,
+        .active_ver =
+            {
+                .comparison_stamp = 0x12345678,
+                .str = {.str_type = PLDM_STR_TYPE_ASCII,
+                        .str_len = activeCompVerStrLen,
+                        .str_data = {}},
+                .date = {},
+            },
+        .pending_ver =
+            {
+                .comparison_stamp = 0x12345678,
+                .str = {.str_type = PLDM_STR_TYPE_ASCII,
+                        .str_len = pendingCompVerStrLen,
+                        .str_data = {}},
+                .date = {},
+            },
+        .comp_activation_methods = inEntry->comp_activation_methods,
+        .capabilities_during_update = inEntry->capabilities_during_update,
+    };
+    // Fill strings
+    std::fill_n(entryFull.active_ver.str.str_data, activeCompVerStrLen, 0xaa);
+    std::fill_n(entryFull.pending_ver.str.str_data, pendingCompVerStrLen, 0xbb);
+    std::fill_n(entryFull.active_ver.date, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
+                0xff);
+    std::fill_n(entryFull.pending_ver.date,
+                PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN, 0xff);
+
+    rc = encode_get_firmware_parameters_resp_comp_entry(
+        &entryFull, enc_data.data(), &enc_payload_len);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(enc_payload_len, entryLength);
+    EXPECT_TRUE(std::equal(entry.begin(), entry.end(), enc_data.begin()));
+#endif
 }
 
 #ifdef LIBPLDM_API_TESTING
@@ -2675,6 +2791,7 @@
 
 TEST(RequestUpdate, goodPathDecodeResponse)
 {
+    /* Test a success completion code */
     constexpr uint16_t fdMetaDataLen = 1024;
     constexpr uint8_t fdWillSendPkgData = 1;
     constexpr std::array<uint8_t, hdrSize + sizeof(pldm_request_update_resp)>
@@ -2695,6 +2812,25 @@
     EXPECT_EQ(outFdMetaDataLen, fdMetaDataLen);
     EXPECT_EQ(outFdWillSendPkgData, fdWillSendPkgData);
 
+#ifdef LIBPLDM_API_TESTING
+    /* Check the success roundtrip matches */
+    PLDM_MSG_DEFINE_P(enc, 1000);
+    size_t enc_payload_len = 1000;
+    const struct pldm_request_update_resp resp_data = {
+        .completion_code = PLDM_SUCCESS,
+        .fd_meta_data_len = outFdMetaDataLen,
+        .fd_will_send_pkg_data = outFdWillSendPkgData,
+    };
+    rc = encode_request_update_resp(FIXED_INSTANCE_ID, &resp_data, enc,
+                                    &enc_payload_len);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(enc_payload_len + hdrSize, requestUpdateResponse1.size());
+    EXPECT_TRUE(std::equal(requestUpdateResponse1.begin() + hdrSize,
+                           requestUpdateResponse1.end(), enc_buf + hdrSize));
+    check_response(enc, PLDM_REQUEST_UPDATE);
+#endif
+
+    /* Test a failure completion code */
     outCompletionCode = 0;
     outFdMetaDataLen = 0;
     outFdWillSendPkgData = 0;
@@ -2786,6 +2922,27 @@
                    0x78, 0x56, 0x34, 0x12, 0x01, 0x0b, 0x30, 0x70, 0x65,
                    0x6e, 0x42, 0x6d, 0x63, 0x76, 0x31, 0x2e, 0x31};
     EXPECT_EQ(request, outRequest);
+
+#ifdef LIBPLDM_API_TESTING
+    /* Check the roundtrip */
+    struct pldm_pass_component_table_req_full req;
+    PLDM_MSG_DEFINE_P(dec, outRequest.size());
+    std::copy(outRequest.begin(), outRequest.end(), dec_buf);
+    rc =
+        decode_pass_component_table_req(dec, outRequest.size() - hdrSize, &req);
+    ASSERT_EQ(rc, 0);
+
+    EXPECT_EQ(req.transfer_flag, PLDM_START_AND_END);
+    EXPECT_EQ(req.comp_classification, PLDM_COMP_FIRMWARE);
+    EXPECT_EQ(req.comp_identifier, compIdentifier);
+    EXPECT_EQ(req.comp_classification_index, compClassificationIndex);
+    EXPECT_EQ(req.comp_comparison_stamp, compComparisonStamp);
+    EXPECT_EQ(req.version.str_type, PLDM_STR_TYPE_ASCII);
+    EXPECT_EQ(req.version.str_len, compVerStrLen);
+    EXPECT_TRUE(std::equal(req.version.str_data,
+                           req.version.str_data + req.version.str_len,
+                           compVerStr.data()));
+#endif
 }
 
 TEST(PassComponentTable, errorPathEncodeRequest)
@@ -3030,6 +3187,27 @@
                    0x00, 0x00, 0x01, 0x0b, 0x4f, 0x70, 0x65, 0x6e, 0x42,
                    0x6d, 0x63, 0x76, 0x32, 0x2e, 0x32};
     EXPECT_EQ(request, outRequest);
+
+#ifdef LIBPLDM_API_TESTING
+    /* Check the roundtrip */
+    struct pldm_update_component_req_full req;
+    PLDM_MSG_DEFINE_P(dec, outRequest.size());
+    std::copy(outRequest.begin(), outRequest.end(), dec_buf);
+    rc = decode_update_component_req(dec, outRequest.size() - hdrSize, &req);
+    ASSERT_EQ(rc, 0);
+
+    EXPECT_EQ(req.comp_classification, PLDM_COMP_FIRMWARE);
+    EXPECT_EQ(req.comp_identifier, compIdentifier);
+    EXPECT_EQ(req.comp_classification_index, compClassificationIndex);
+    EXPECT_EQ(req.comp_comparison_stamp, compComparisonStamp);
+    EXPECT_EQ(req.comp_image_size, compImageSize);
+    EXPECT_EQ(req.update_option_flags.value, updateOptionFlags.value);
+    EXPECT_EQ(req.version.str_type, PLDM_STR_TYPE_ASCII);
+    EXPECT_EQ(req.version.str_len, compVerStrLen);
+    EXPECT_TRUE(std::equal(req.version.str_data,
+                           req.version.str_data + req.version.str_len,
+                           compVerStr.data()));
+#endif
 }
 
 TEST(UpdateComponent, errorPathEncodeRequest)
@@ -3872,6 +4050,30 @@
     EXPECT_EQ(reasonCode, PLDM_FD_TIMEOUT_DOWNLOAD);
     EXPECT_EQ(updateOptionFlagsEnabled.value, updateOptionFlagsEnabled2);
 
+#ifdef LIBPLDM_API_TESTING
+    /* Check the roundtrip */
+    PLDM_MSG_DEFINE_P(enc, 1000);
+    size_t enc_payload_len = 1000;
+    const struct pldm_get_status_resp status_enc = {
+        .completion_code = PLDM_SUCCESS,
+        .current_state = currentState,
+        .previous_state = previousState,
+        .aux_state = auxState,
+        .aux_state_status = auxStateStatus,
+        .progress_percent = progressPercent,
+        .reason_code = reasonCode,
+        .update_option_flags_enabled = updateOptionFlagsEnabled,
+    };
+    rc = encode_get_status_resp(FIXED_INSTANCE_ID, &status_enc, enc,
+                                &enc_payload_len);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(enc_payload_len + hdrSize, getStatusResponse2.size());
+    EXPECT_TRUE(std::equal(getStatusResponse2.begin() + hdrSize,
+                           getStatusResponse2.end(), enc_buf + hdrSize));
+    check_response(enc, PLDM_GET_STATUS);
+#endif
+
+    /* Check a not-ready completion code */
     constexpr std::array<uint8_t, hdrSize + sizeof(completionCode)>
         getStatusResponse3{0x00, 0x00, 0x00, 0x04};
     auto responseMsg3 =