| /* |
| * SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & |
| * AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "base.h" |
| #include "debug-token.h" |
| #include "device-configuration.h" |
| #include "diagnostics.h" |
| #include "firmware-utils.h" |
| #include "network-ports.h" |
| #include "pci-links.h" |
| #include "platform-environmental.h" |
| #include "powersmoothing-powerprofile-api-v2.h" |
| |
| #include "common/event.hpp" |
| #include "utils.hpp" |
| |
| #include <cstdio> |
| #include <fstream> |
| #include <functional> |
| |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| using ::testing::Test; |
| |
| #define private public |
| #define protected public |
| #include "mockupResponder.hpp" |
| |
| // ============================================================================= |
| // Test fixture matching the existing pattern |
| // ============================================================================= |
| |
| class MockupResponderBranchTest : public Test |
| { |
| protected: |
| MockupResponderBranchTest() |
| { |
| init(31, NSM_DEV_ID_GPU, 3); |
| } |
| |
| uint8_t instanceId = 0; |
| common::Event event; |
| boost::asio::io_context io; |
| std::shared_ptr<sdbusplus::asio::connection> systemBus; |
| std::shared_ptr<sdbusplus::asio::object_server> objServer; |
| std::shared_ptr<MockupResponder::MockupResponder> mockupResponder; |
| |
| void init(eid_t eid, uint8_t deviceType, uint8_t instId) |
| { |
| this->instanceId = instId; |
| systemBus = std::make_shared<sdbusplus::asio::connection>(io); |
| objServer = std::make_shared<sdbusplus::asio::object_server>(systemBus); |
| mockupResponder = std::make_shared<MockupResponder::MockupResponder>( |
| true, event, *objServer, eid, deviceType, instId); |
| } |
| }; |
| |
| // ============================================================================= |
| // processRxMsg branch coverage |
| // ============================================================================= |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgInvalidHeader) |
| { |
| // Zero-length or invalid header should return nullopt |
| std::vector<uint8_t> rxMsg(sizeof(nsm_msg_hdr), 0); |
| // Corrupt the header so unpack_nsm_header fails |
| memset(rxMsg.data(), 0, rxMsg.size()); |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(rxMsg, longRunning); |
| // unpack_nsm_header with zeroed header may fail |
| // Result depends on implementation, but should not crash |
| } |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgEventAcknowledgement) |
| { |
| // Build a valid NSM message with type = EVENT_ACKNOWLEDGMENT |
| std::vector<uint8_t> rxMsg(sizeof(nsm_msg_hdr) + 1, 0); |
| auto hdr = reinterpret_cast<nsm_msg_hdr*>(rxMsg.data()); |
| nsm_header_info info{}; |
| info.nsm_msg_type = NSM_EVENT_ACKNOWLEDGMENT; |
| info.instance_id = instanceId; |
| info.nvidia_msg_type = NSM_TYPE_DEVICE_CAPABILITY_DISCOVERY; |
| [[maybe_unused]] auto rc = pack_nsm_header(&info, hdr); |
| |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(rxMsg, longRunning); |
| // Event ack returns nullopt |
| EXPECT_FALSE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgUnsupportedMsgType) |
| { |
| // Build a message with unsupported nvidia_msg_type |
| std::vector<uint8_t> rxMsg(sizeof(nsm_msg_hdr) + 2, 0); |
| auto hdr = reinterpret_cast<nsm_msg_hdr*>(rxMsg.data()); |
| nsm_header_info info{}; |
| info.nsm_msg_type = NSM_REQUEST; |
| info.instance_id = instanceId; |
| info.nvidia_msg_type = 0x7F; // unsupported type |
| [[maybe_unused]] auto rc = pack_nsm_header(&info, hdr); |
| auto msg = reinterpret_cast<nsm_msg*>(rxMsg.data()); |
| msg->payload[0] = 0x00; // command code |
| |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(rxMsg, longRunning); |
| // Should return unsupported command response |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgType0UnsupportedCommand) |
| { |
| // Type 0 with unsupported command code |
| std::vector<uint8_t> rxMsg(sizeof(nsm_msg_hdr) + 2, 0); |
| auto hdr = reinterpret_cast<nsm_msg_hdr*>(rxMsg.data()); |
| nsm_header_info info{}; |
| info.nsm_msg_type = NSM_REQUEST; |
| info.instance_id = instanceId; |
| info.nvidia_msg_type = NSM_TYPE_DEVICE_CAPABILITY_DISCOVERY; |
| [[maybe_unused]] auto rc = pack_nsm_header(&info, hdr); |
| auto msg = reinterpret_cast<nsm_msg*>(rxMsg.data()); |
| msg->payload[0] = 0xFE; // unsupported command |
| |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(rxMsg, longRunning); |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgType1UnsupportedCommand) |
| { |
| // Type 1 (Network Port) with unsupported command code |
| std::vector<uint8_t> rxMsg(sizeof(nsm_msg_hdr) + 2, 0); |
| auto hdr = reinterpret_cast<nsm_msg_hdr*>(rxMsg.data()); |
| nsm_header_info info{}; |
| info.nsm_msg_type = NSM_REQUEST; |
| info.instance_id = instanceId; |
| info.nvidia_msg_type = NSM_TYPE_NETWORK_PORT; |
| [[maybe_unused]] auto rc = pack_nsm_header(&info, hdr); |
| auto msg = reinterpret_cast<nsm_msg*>(rxMsg.data()); |
| msg->payload[0] = 0xFE; |
| |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(rxMsg, longRunning); |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgType2UnsupportedCommand) |
| { |
| // Type 2 (PCI Link) with unsupported command code |
| std::vector<uint8_t> rxMsg(sizeof(nsm_msg_hdr) + 2, 0); |
| auto hdr = reinterpret_cast<nsm_msg_hdr*>(rxMsg.data()); |
| nsm_header_info info{}; |
| info.nsm_msg_type = NSM_REQUEST; |
| info.instance_id = instanceId; |
| info.nvidia_msg_type = NSM_TYPE_PCI_LINK; |
| [[maybe_unused]] auto rc = pack_nsm_header(&info, hdr); |
| auto msg = reinterpret_cast<nsm_msg*>(rxMsg.data()); |
| msg->payload[0] = 0xFE; |
| |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(rxMsg, longRunning); |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgType3UnsupportedCommand) |
| { |
| // Type 3 (Platform Environmental) with unsupported command code |
| std::vector<uint8_t> rxMsg(sizeof(nsm_msg_hdr) + 2, 0); |
| auto hdr = reinterpret_cast<nsm_msg_hdr*>(rxMsg.data()); |
| nsm_header_info info{}; |
| info.nsm_msg_type = NSM_REQUEST; |
| info.instance_id = instanceId; |
| info.nvidia_msg_type = NSM_TYPE_PLATFORM_ENVIRONMENTAL; |
| [[maybe_unused]] auto rc = pack_nsm_header(&info, hdr); |
| auto msg = reinterpret_cast<nsm_msg*>(rxMsg.data()); |
| msg->payload[0] = 0xFE; |
| |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(rxMsg, longRunning); |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgType4UnsupportedCommand) |
| { |
| // Type 4 (Diagnostic) with unsupported command code |
| std::vector<uint8_t> rxMsg(sizeof(nsm_msg_hdr) + 2, 0); |
| auto hdr = reinterpret_cast<nsm_msg_hdr*>(rxMsg.data()); |
| nsm_header_info info{}; |
| info.nsm_msg_type = NSM_REQUEST; |
| info.instance_id = instanceId; |
| info.nvidia_msg_type = NSM_TYPE_DIAGNOSTIC; |
| [[maybe_unused]] auto rc = pack_nsm_header(&info, hdr); |
| auto msg = reinterpret_cast<nsm_msg*>(rxMsg.data()); |
| msg->payload[0] = 0xFE; |
| |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(rxMsg, longRunning); |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgType5UnsupportedCommand) |
| { |
| // Type 5 (Device Configuration) with unsupported command code |
| std::vector<uint8_t> rxMsg(sizeof(nsm_msg_hdr) + 2, 0); |
| auto hdr = reinterpret_cast<nsm_msg_hdr*>(rxMsg.data()); |
| nsm_header_info info{}; |
| info.nsm_msg_type = NSM_REQUEST; |
| info.instance_id = instanceId; |
| info.nvidia_msg_type = NSM_TYPE_DEVICE_CONFIGURATION; |
| [[maybe_unused]] auto rc = pack_nsm_header(&info, hdr); |
| auto msg = reinterpret_cast<nsm_msg*>(rxMsg.data()); |
| msg->payload[0] = 0xFE; |
| |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(rxMsg, longRunning); |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgType6UnsupportedCommand) |
| { |
| // Type 6 (Firmware) with unsupported command code |
| std::vector<uint8_t> rxMsg(sizeof(nsm_msg_hdr) + 2, 0); |
| auto hdr = reinterpret_cast<nsm_msg_hdr*>(rxMsg.data()); |
| nsm_header_info info{}; |
| info.nsm_msg_type = NSM_REQUEST; |
| info.instance_id = instanceId; |
| info.nvidia_msg_type = NSM_TYPE_FIRMWARE; |
| [[maybe_unused]] auto rc = pack_nsm_header(&info, hdr); |
| auto msg = reinterpret_cast<nsm_msg*>(rxMsg.data()); |
| msg->payload[0] = 0xFE; |
| |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(rxMsg, longRunning); |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| // ============================================================================= |
| // processRxMsg dispatching to known handlers |
| // ============================================================================= |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgPingHandler) |
| { |
| Request request(sizeof(nsm_msg_hdr) + sizeof(nsm_common_req)); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| [[maybe_unused]] auto rc = encode_ping_req(instanceId, requestMsg); |
| |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(request, longRunning); |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgGetSupportedMessageTypes) |
| { |
| Request request(sizeof(nsm_msg_hdr) + sizeof(nsm_common_req)); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| [[maybe_unused]] auto rc = |
| encode_get_supported_nvidia_message_types_req(instanceId, requestMsg); |
| |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(request, longRunning); |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgGetSupportedCommandCodes) |
| { |
| Request request(sizeof(nsm_msg_hdr) + |
| sizeof(nsm_get_supported_command_codes_req)); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| [[maybe_unused]] auto rc = encode_get_supported_command_codes_req( |
| instanceId, NSM_TYPE_DEVICE_CAPABILITY_DISCOVERY, requestMsg); |
| |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(request, longRunning); |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgQueryDeviceIdentification) |
| { |
| Request request(sizeof(nsm_msg_hdr) + |
| sizeof(nsm_query_device_identification_req)); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| [[maybe_unused]] auto rc = |
| encode_nsm_query_device_identification_req(instanceId, requestMsg); |
| |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(request, longRunning); |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| // ============================================================================= |
| // Type 1 (Network Port) handler dispatch via processRxMsg |
| // ============================================================================= |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgGetPortTelemetryCounter) |
| { |
| Request request(sizeof(nsm_msg_hdr) + |
| sizeof(nsm_get_port_telemetry_counter_req)); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| [[maybe_unused]] auto rc = |
| encode_get_port_telemetry_counter_req(instanceId, 0, requestMsg); |
| |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(request, longRunning); |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgQueryPortCharacteristics) |
| { |
| Request request(sizeof(nsm_msg_hdr) + |
| sizeof(nsm_query_port_characteristics_req)); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| [[maybe_unused]] auto rc = |
| encode_query_port_characteristics_req(instanceId, 0, requestMsg); |
| |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(request, longRunning); |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgQueryPortStatus) |
| { |
| Request request(sizeof(nsm_msg_hdr) + sizeof(nsm_query_port_status_req)); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| [[maybe_unused]] auto rc = encode_query_port_status_req(instanceId, 0, |
| requestMsg); |
| |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(request, longRunning); |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgGetFabricManagerState) |
| { |
| Request request(sizeof(nsm_msg_hdr) + sizeof(nsm_common_req)); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| [[maybe_unused]] auto rc = encode_get_fabric_manager_state_req(instanceId, |
| requestMsg); |
| |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(request, longRunning); |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgQueryPortsAvailable) |
| { |
| Request request(sizeof(nsm_msg_hdr) + sizeof(nsm_common_req)); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| [[maybe_unused]] auto rc = encode_query_ports_available_req(instanceId, |
| requestMsg); |
| |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(request, longRunning); |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| // ============================================================================= |
| // Type 3 (Platform Environmental) handler dispatch via processRxMsg |
| // ============================================================================= |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgGetInventoryInformation) |
| { |
| Request request(sizeof(nsm_msg_hdr) + |
| sizeof(nsm_get_inventory_information_req)); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| [[maybe_unused]] auto rc = encode_get_inventory_information_req( |
| instanceId, BOARD_PART_NUMBER, requestMsg); |
| |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(request, longRunning); |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgGetTemperatureReading) |
| { |
| Request request(sizeof(nsm_msg_hdr) + |
| sizeof(nsm_get_temperature_reading_req)); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| [[maybe_unused]] auto rc = encode_get_temperature_reading_req(instanceId, 0, |
| requestMsg); |
| |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(request, longRunning); |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgGetTemperatureReadingAggregate) |
| { |
| Request request(sizeof(nsm_msg_hdr) + |
| sizeof(nsm_get_temperature_reading_req)); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| [[maybe_unused]] auto rc = |
| encode_get_temperature_reading_req(instanceId, 255, requestMsg); |
| |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(request, longRunning); |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgGetCurrentPowerDraw) |
| { |
| Request request(sizeof(nsm_msg_hdr) + |
| sizeof(nsm_get_current_power_draw_req)); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| [[maybe_unused]] auto rc = encode_get_current_power_draw_req(instanceId, 0, |
| 0, requestMsg); |
| |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(request, longRunning); |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgGetCurrentPowerDrawAggregate) |
| { |
| Request request(sizeof(nsm_msg_hdr) + |
| sizeof(nsm_get_current_power_draw_req)); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| [[maybe_unused]] auto rc = |
| encode_get_current_power_draw_req(instanceId, 255, 0, requestMsg); |
| |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(request, longRunning); |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgGetMaxObservedPower) |
| { |
| Request request(sizeof(nsm_msg_hdr) + |
| sizeof(nsm_get_max_observed_power_req)); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| [[maybe_unused]] auto rc = encode_get_max_observed_power_req(instanceId, 0, |
| 0, requestMsg); |
| |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(request, longRunning); |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgGetMaxObservedPowerAggregate) |
| { |
| Request request(sizeof(nsm_msg_hdr) + |
| sizeof(nsm_get_max_observed_power_req)); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| [[maybe_unused]] auto rc = |
| encode_get_max_observed_power_req(instanceId, 255, 0, requestMsg); |
| |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(request, longRunning); |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgGetEccErrorCounts) |
| { |
| Request request(sizeof(nsm_msg_hdr) + sizeof(nsm_common_req)); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| [[maybe_unused]] auto rc = encode_get_ECC_error_counts_req(instanceId, |
| requestMsg); |
| |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(request, longRunning); |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgGetDriverInfo) |
| { |
| Request request(sizeof(nsm_msg_hdr) + sizeof(nsm_common_req)); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| [[maybe_unused]] auto rc = encode_get_driver_info_req(instanceId, |
| requestMsg); |
| |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(request, longRunning); |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| // ============================================================================= |
| // Handler decode error paths (nullptr and short length) |
| // ============================================================================= |
| |
| TEST_F(MockupResponderBranchTest, PingHandlerDirectCall) |
| { |
| Request request(sizeof(nsm_msg_hdr) + sizeof(nsm_common_req)); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| [[maybe_unused]] auto rc = encode_ping_req(instanceId, requestMsg); |
| |
| auto resp = mockupResponder->pingHandler(requestMsg, request.size()); |
| EXPECT_TRUE(resp.has_value()); |
| EXPECT_EQ(resp->size(), sizeof(nsm_msg_hdr) + sizeof(nsm_common_resp)); |
| } |
| |
| TEST_F(MockupResponderBranchTest, UnsupportedCommandHandlerDirectCall) |
| { |
| Request request(sizeof(nsm_msg_hdr) + sizeof(nsm_common_req)); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| [[maybe_unused]] auto rc = encode_ping_req(instanceId, requestMsg); |
| |
| auto resp = mockupResponder->unsupportedCommandHandler(requestMsg, |
| request.size()); |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPortTelemetryCounterBadDecode) |
| { |
| // Short buffer for decode to fail |
| Request request(sizeof(nsm_msg_hdr), 0); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| auto resp = mockupResponder->getPortTelemetryCounterHandler(requestMsg, |
| request.size()); |
| EXPECT_FALSE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, QueryPortCharacteristicsBadDecode) |
| { |
| Request request(sizeof(nsm_msg_hdr), 0); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| auto resp = mockupResponder->queryPortCharacteristicsHandler( |
| requestMsg, request.size()); |
| EXPECT_FALSE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, QueryPortStatusBadDecode) |
| { |
| Request request(sizeof(nsm_msg_hdr), 0); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| auto resp = mockupResponder->queryPortStatusHandler(requestMsg, |
| request.size()); |
| EXPECT_FALSE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetFabricManagerStateBadDecode) |
| { |
| Request request(sizeof(nsm_msg_hdr), 0); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| auto resp = mockupResponder->getFabricManagerStateHandler(requestMsg, |
| request.size()); |
| EXPECT_FALSE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, QueryPortsAvailableBadDecode) |
| { |
| Request request(sizeof(nsm_msg_hdr), 0); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| auto resp = mockupResponder->queryPortsAvailableHandler(requestMsg, |
| request.size()); |
| EXPECT_FALSE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, SetPortDisableFutureBadDecode) |
| { |
| Request request(sizeof(nsm_msg_hdr), 0); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| auto resp = mockupResponder->setPortDisableFutureHandler(requestMsg, |
| request.size()); |
| EXPECT_FALSE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPortDisableFutureBadDecode) |
| { |
| Request request(sizeof(nsm_msg_hdr), 0); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| auto resp = mockupResponder->getPortDisableFutureHandler(requestMsg, |
| request.size()); |
| EXPECT_FALSE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPowerModeBadDecode) |
| { |
| Request request(sizeof(nsm_msg_hdr), 0); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| auto resp = mockupResponder->getPowerModeHandler(requestMsg, |
| request.size()); |
| EXPECT_FALSE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, SetPowerModeBadDecode) |
| { |
| Request request(sizeof(nsm_msg_hdr), 0); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| auto resp = mockupResponder->setPowerModeHandler(requestMsg, |
| request.size()); |
| EXPECT_FALSE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetSwitchIsolationModeBadDecode) |
| { |
| Request request(sizeof(nsm_msg_hdr), 0); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| auto resp = mockupResponder->getSwitchIsolationMode(requestMsg, |
| request.size()); |
| EXPECT_FALSE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, SetSwitchIsolationModeBadDecode) |
| { |
| Request request(sizeof(nsm_msg_hdr), 0); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| auto resp = mockupResponder->setSwitchIsolationMode(requestMsg, |
| request.size()); |
| EXPECT_FALSE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetInventoryInformationBadDecode) |
| { |
| Request request(sizeof(nsm_msg_hdr), 0); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| auto resp = mockupResponder->getInventoryInformationHandler(requestMsg, |
| request.size()); |
| EXPECT_FALSE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, ReadThermalParameterBadDecode) |
| { |
| Request request(sizeof(nsm_msg_hdr), 0); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| auto resp = mockupResponder->readThermalParameterHandler(requestMsg, |
| request.size()); |
| EXPECT_FALSE(resp.has_value()); |
| } |
| |
| // ============================================================================= |
| // getProperty branch coverage (different property identifiers) |
| // ============================================================================= |
| |
| TEST_F(MockupResponderBranchTest, GetPropertyBoardPartNumber) |
| { |
| auto res = mockupResponder->getProperty(BOARD_PART_NUMBER); |
| EXPECT_GT(res.size(), 0u); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPropertyFruPartNumber) |
| { |
| auto res = mockupResponder->getProperty(FRU_PART_NUMBER); |
| EXPECT_GT(res.size(), 0u); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPropertySerialNumber) |
| { |
| auto res = mockupResponder->getProperty(SERIAL_NUMBER); |
| EXPECT_GT(res.size(), 0u); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPropertyMarketingName) |
| { |
| auto res = mockupResponder->getProperty(MARKETING_NAME); |
| EXPECT_GT(res.size(), 0u); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPropertyBuildDate) |
| { |
| auto res = mockupResponder->getProperty(BUILD_DATE); |
| EXPECT_GT(res.size(), 0u); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPropertyDeviceGuid) |
| { |
| auto res = mockupResponder->getProperty(DEVICE_GUID); |
| EXPECT_EQ(res.size(), 16u); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPropertyAssetTag) |
| { |
| auto res = mockupResponder->getProperty(ASSET_TAG); |
| EXPECT_GT(res.size(), 0u); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPropertyInfoRomVersion) |
| { |
| auto res = mockupResponder->getProperty(INFO_ROM_VERSION); |
| EXPECT_GT(res.size(), 0u); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPropertyProductLength) |
| { |
| auto res = mockupResponder->getProperty(PRODUCT_LENGTH); |
| EXPECT_EQ(res.size(), sizeof(uint32_t)); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPropertyProductWidth) |
| { |
| auto res = mockupResponder->getProperty(PRODUCT_WIDTH); |
| EXPECT_EQ(res.size(), sizeof(uint32_t)); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPropertyProductHeight) |
| { |
| auto res = mockupResponder->getProperty(PRODUCT_HEIGHT); |
| EXPECT_EQ(res.size(), sizeof(uint32_t)); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPropertyRatedModulePowerLimit) |
| { |
| auto res = mockupResponder->getProperty(RATED_MODULE_POWER_LIMIT); |
| EXPECT_EQ(res.size(), sizeof(uint32_t)); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPropertyMaximumModulePowerLimit) |
| { |
| auto res = mockupResponder->getProperty(MAXIMUM_MODULE_POWER_LIMIT); |
| EXPECT_EQ(res.size(), sizeof(uint32_t)); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPropertyMinimumModulePowerLimit) |
| { |
| auto res = mockupResponder->getProperty(MINIMUM_MODULE_POWER_LIMIT); |
| EXPECT_EQ(res.size(), sizeof(uint32_t)); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPropertyMinimumDevicePowerLimit) |
| { |
| auto res = mockupResponder->getProperty(MINIMUM_DEVICE_POWER_LIMIT); |
| EXPECT_EQ(res.size(), sizeof(uint32_t)); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPropertyMaximumDevicePowerLimit) |
| { |
| auto res = mockupResponder->getProperty(MAXIMUM_DEVICE_POWER_LIMIT); |
| EXPECT_EQ(res.size(), sizeof(uint32_t)); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPropertyRatedDevicePowerLimit) |
| { |
| auto res = mockupResponder->getProperty(RATED_DEVICE_POWER_LIMIT); |
| EXPECT_EQ(res.size(), sizeof(uint32_t)); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPropertyMinEdppScalingFactor) |
| { |
| auto res = mockupResponder->getProperty(MINIMUM_EDPP_SCALING_FACTOR); |
| EXPECT_EQ(res.size(), 1u); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPropertyMaxEdppScalingFactor) |
| { |
| auto res = mockupResponder->getProperty(MAXIMUM_EDPP_SCALING_FACTOR); |
| EXPECT_EQ(res.size(), 1u); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPropertyMinGraphicsClockLimit) |
| { |
| auto res = mockupResponder->getProperty(MINIMUM_GRAPHICS_CLOCK_LIMIT); |
| EXPECT_EQ(res.size(), sizeof(uint32_t)); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPropertyMaxGraphicsClockLimit) |
| { |
| auto res = mockupResponder->getProperty(MAXIMUM_GRAPHICS_CLOCK_LIMIT); |
| EXPECT_EQ(res.size(), sizeof(uint32_t)); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPropertyDefaultBoostClocks) |
| { |
| auto res = mockupResponder->getProperty(DEFAULT_BOOST_CLOCKS); |
| EXPECT_EQ(res.size(), sizeof(uint32_t)); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPropertyDefaultBaseClocks) |
| { |
| auto res = mockupResponder->getProperty(DEFAULT_BASE_CLOCKS); |
| EXPECT_EQ(res.size(), sizeof(uint32_t)); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPropertyMinMemoryClockLimit) |
| { |
| auto res = mockupResponder->getProperty(MINIMUM_MEMORY_CLOCK_LIMIT); |
| EXPECT_EQ(res.size(), sizeof(uint32_t)); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPropertyMaxMemoryClockLimit) |
| { |
| auto res = mockupResponder->getProperty(MAXIMUM_MEMORY_CLOCK_LIMIT); |
| EXPECT_EQ(res.size(), sizeof(uint32_t)); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPropertyRatedGpuBasePowerLimit) |
| { |
| auto res = mockupResponder->getProperty(RATED_GPU_BASE_POWER_LIMIT); |
| EXPECT_EQ(res.size(), sizeof(uint32_t)); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPropertyMinGpuBasePowerLimit) |
| { |
| auto res = mockupResponder->getProperty(MINIMUM_GPU_BASE_POWER_LIMIT); |
| EXPECT_EQ(res.size(), sizeof(uint32_t)); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPropertyMaxGpuBasePowerLimit) |
| { |
| auto res = mockupResponder->getProperty(MAXIMUM_GPU_BASE_POWER_LIMIT); |
| EXPECT_EQ(res.size(), sizeof(uint32_t)); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPropertyPcieRetimerEepromVersion) |
| { |
| auto res = mockupResponder->getProperty(PCIERETIMER_0_EEPROM_VERSION); |
| EXPECT_EQ(res.size(), 8u); |
| auto res1 = mockupResponder->getProperty(PCIERETIMER_1_EEPROM_VERSION); |
| EXPECT_EQ(res1.size(), 8u); |
| auto res7 = mockupResponder->getProperty(PCIERETIMER_7_EEPROM_VERSION); |
| EXPECT_EQ(res7.size(), 8u); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPropertyDevicePartNumber) |
| { |
| auto res = mockupResponder->getProperty(DEVICE_PART_NUMBER); |
| EXPECT_GT(res.size(), 0u); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPropertyMaxMemoryCapacity) |
| { |
| auto res = mockupResponder->getProperty(MAXIMUM_MEMORY_CAPACITY); |
| EXPECT_EQ(res.size(), sizeof(uint32_t)); |
| } |
| |
| TEST_F(MockupResponderBranchTest, GetPropertyUnknownReturnsEmpty) |
| { |
| auto res = mockupResponder->getProperty(0xFF); |
| EXPECT_TRUE(res.empty()); |
| } |
| |
| // ============================================================================= |
| // getSupportCommandCodeHandler branch coverage |
| // ============================================================================= |
| |
| TEST_F(MockupResponderBranchTest, GetSupportedCommandCodesInvalidType) |
| { |
| // Use nvidia_msg_type >= NUM_NSM_TYPES to trigger the error branch |
| Request request(sizeof(nsm_msg_hdr) + |
| sizeof(nsm_get_supported_command_codes_req)); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| [[maybe_unused]] auto rc = encode_get_supported_command_codes_req( |
| instanceId, NSM_TYPE_DEVICE_CAPABILITY_DISCOVERY, requestMsg); |
| // Override the nvidia_message_type field in payload to invalid |
| auto reqPayload = reinterpret_cast<nsm_get_supported_command_codes_req*>( |
| requestMsg->payload); |
| reqPayload->nvidia_message_type = 0xFF; // Invalid |
| |
| auto resp = mockupResponder->getSupportCommandCodeHandler(requestMsg, |
| request.size()); |
| EXPECT_FALSE(resp.has_value()); |
| } |
| |
| // ============================================================================= |
| // EventSource constructor branch coverage |
| // ============================================================================= |
| |
| TEST(EventSourceBranch, EmptyEvents) |
| { |
| MockupResponder::EventSource es(std::vector<uint64_t>{}); |
| // All bits should be zero |
| for (auto& e : es.events) |
| { |
| EXPECT_EQ(e.byte, 0u); |
| } |
| } |
| |
| TEST(EventSourceBranch, ValidEvents) |
| { |
| MockupResponder::EventSource es(std::vector<uint64_t>{0, 1, 8, 15, 63}); |
| // bit 0 in byte 0 |
| EXPECT_NE(es.events[0].byte & 0x01, 0); |
| // bit 1 in byte 0 |
| EXPECT_NE(es.events[0].byte & 0x02, 0); |
| // bit 0 in byte 1 |
| EXPECT_NE(es.events[1].byte & 0x01, 0); |
| // bit 7 in byte 1 |
| EXPECT_NE(es.events[1].byte & 0x80, 0); |
| // bit 7 in byte 7 |
| EXPECT_NE(es.events[7].byte & 0x80, 0); |
| } |
| |
| TEST(EventSourceBranch, EventBeyondRange) |
| { |
| // event >= EVENT_SOURCES_LENGTH * 8 should be ignored |
| MockupResponder::EventSource es( |
| std::vector<uint64_t>{EVENT_SOURCES_LENGTH * 8}); |
| for (auto& e : es.events) |
| { |
| EXPECT_EQ(e.byte, 0u); |
| } |
| } |
| |
| TEST(EventSourceBranch, EventAtBoundary) |
| { |
| // event == EVENT_SOURCES_LENGTH * 8 - 1 should be accepted |
| uint64_t maxEvent = EVENT_SOURCES_LENGTH * 8 - 1; |
| MockupResponder::EventSource es(std::vector<uint64_t>{maxEvent}); |
| auto idx = maxEvent >> 3; |
| auto bit = maxEvent & 0x7; |
| EXPECT_NE(es.events[idx].byte & (1u << bit), 0u); |
| } |
| |
| // ============================================================================= |
| // ReadThermalParameter handler branches |
| // ============================================================================= |
| |
| TEST_F(MockupResponderBranchTest, ReadThermalParameterSingleSensor) |
| { |
| Request request(sizeof(nsm_msg_hdr) + |
| sizeof(nsm_read_thermal_parameter_req)); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| // Set up a valid request for parameter_id != 255 |
| auto reqPayload = |
| reinterpret_cast<nsm_read_thermal_parameter_req*>(requestMsg->payload); |
| nsm_header_info info{}; |
| info.nsm_msg_type = NSM_REQUEST; |
| info.instance_id = instanceId; |
| info.nvidia_msg_type = NSM_TYPE_PLATFORM_ENVIRONMENTAL; |
| [[maybe_unused]] auto rc = pack_nsm_header(&info, &requestMsg->hdr); |
| reqPayload->hdr.command = NSM_READ_THERMAL_PARAMETER; |
| reqPayload->hdr.data_size = 1; |
| reqPayload->parameter_id = 0; // Not aggregate |
| |
| auto resp = mockupResponder->readThermalParameterHandler(requestMsg, |
| request.size()); |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, ReadThermalParameterAggregate) |
| { |
| Request request(sizeof(nsm_msg_hdr) + |
| sizeof(nsm_read_thermal_parameter_req)); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| auto reqPayload = |
| reinterpret_cast<nsm_read_thermal_parameter_req*>(requestMsg->payload); |
| nsm_header_info info{}; |
| info.nsm_msg_type = NSM_REQUEST; |
| info.instance_id = instanceId; |
| info.nvidia_msg_type = NSM_TYPE_PLATFORM_ENVIRONMENTAL; |
| [[maybe_unused]] auto rc = pack_nsm_header(&info, &requestMsg->hdr); |
| reqPayload->hdr.command = NSM_READ_THERMAL_PARAMETER; |
| reqPayload->hdr.data_size = 1; |
| reqPayload->parameter_id = 255; // Aggregate |
| |
| auto resp = mockupResponder->readThermalParameterHandler(requestMsg, |
| request.size()); |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| // ============================================================================= |
| // Type 5 (Device Configuration) handler dispatch |
| // ============================================================================= |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgGetErrorInjectionModeV1) |
| { |
| Request request(sizeof(nsm_msg_hdr) + sizeof(nsm_common_req)); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| [[maybe_unused]] auto rc = |
| encode_get_error_injection_mode_v1_req(instanceId, requestMsg); |
| |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(request, longRunning); |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgGetReconfigurationPermissionsV1) |
| { |
| Request request(sizeof(nsm_msg_hdr) + |
| sizeof(nsm_get_reconfiguration_permissions_v1_req)); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| [[maybe_unused]] auto rc = encode_get_reconfiguration_permissions_v1_req( |
| instanceId, RP_IN_SYSTEM_TEST, requestMsg); |
| |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(request, longRunning); |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| // ============================================================================= |
| // Type 2 (PCI Link) handler dispatch |
| // ============================================================================= |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgQueryScalarGroupTelemetry) |
| { |
| Request request(sizeof(nsm_msg_hdr) + |
| sizeof(nsm_query_scalar_group_telemetry_v1_req)); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| [[maybe_unused]] auto rc = encode_query_scalar_group_telemetry_v1_req( |
| instanceId, 0, GROUP_ID_10, requestMsg); |
| |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(request, longRunning); |
| EXPECT_TRUE(resp.has_value()); |
| } |
| |
| // ============================================================================= |
| // Type 6 (Firmware) handler dispatch |
| // ============================================================================= |
| |
| TEST_F(MockupResponderBranchTest, ProcessRxMsgFirmwareGetRotInfo) |
| { |
| // Use the proper encode function with required struct |
| nsm_firmware_erot_state_info_req fw_req{}; |
| fw_req.component_classification = 0; |
| fw_req.component_classification_index = 0; |
| fw_req.component_identifier = 0; |
| |
| Request request(sizeof(nsm_msg_hdr) + |
| sizeof(nsm_firmware_get_erot_state_info_req)); |
| auto requestMsg = reinterpret_cast<nsm_msg*>(request.data()); |
| [[maybe_unused]] auto rc = encode_nsm_query_get_erot_state_parameters_req( |
| instanceId, &fw_req, requestMsg); |
| |
| std::optional<Request> longRunning; |
| auto resp = mockupResponder->processRxMsg(request, longRunning); |
| EXPECT_TRUE(resp.has_value()); |
| } |