blob: 075889f5673c929465830deb61f27550ce004b02 [file] [log] [blame] [edit]
/**
* @brief Unit tests for mock device
*
* SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES.
* All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
#include "server/mock_device.hpp"
#include "libnsm/base.h"
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <chrono>
using namespace testing;
using namespace gpu::telemetry;
using namespace std::chrono_literals;
class MockDeviceTest : public Test {
protected:
void SetUp() override {
config_.temperature.min = 30.0f;
config_.temperature.max = 80.0f;
config_.responseDelay = 0ms;
config_.simulateErrors = false;
device_ = std::make_unique<MockDevice>(config_);
}
// Helper to create temperature request
std::vector<uint8_t> createTempRequest() {
nsm_msg request = {};
encode_common_req(0x01, NSM_TYPE_TEMPERATURE,
NSM_GET_TEMPERATURE_READING, &request);
return std::vector<uint8_t>(
reinterpret_cast<uint8_t*>(&request),
reinterpret_cast<uint8_t*>(&request) + sizeof(request));
}
// Helper to verify temperature response
void verifyTempResponse(std::span<const std::uint8_t> response) {
ASSERT_GE(response.size(), sizeof(nsm_msg));
const nsm_msg* msg = reinterpret_cast<const nsm_msg*>(response.data());
// Check header
EXPECT_EQ(msg->header[0], NSM_SUCCESS);
uint16_t dataSize = *reinterpret_cast<const uint16_t*>(&msg->header[1]);
EXPECT_EQ(dataSize, sizeof(float));
uint16_t reason = *reinterpret_cast<const uint16_t*>(&msg->header[3]);
EXPECT_EQ(reason, 0);
// Check temperature value
float temp = *reinterpret_cast<const float*>(msg->payload);
EXPECT_GE(temp, config_.temperature.min);
EXPECT_LE(temp, config_.temperature.max);
}
MockDeviceConfig config_;
std::unique_ptr<MockDevice> device_;
std::vector<uint8_t> lastResponse_;
bool responseReceived_{false};
};
TEST_F(MockDeviceTest, TemperatureRequest) {
auto request = createTempRequest();
stdexec::sync_wait(device_->sendMessage(
request,
[this](auto response) {
lastResponse_.assign(response.begin(), response.end());
responseReceived_ = true;
}));
ASSERT_TRUE(responseReceived_);
verifyTempResponse(lastResponse_);
}
TEST_F(MockDeviceTest, TemperatureRange) {
// Test multiple temperature readings
std::vector<float> temperatures;
for (int i = 0; i < 100; i++) {
auto request = createTempRequest();
stdexec::sync_wait(device_->sendMessage(
request,
[&temperatures](auto response) {
const nsm_msg* msg =
reinterpret_cast<const nsm_msg*>(response.data());
float temp = *reinterpret_cast<const float*>(msg->payload);
temperatures.push_back(temp);
}));
}
// Verify temperature distribution
ASSERT_EQ(temperatures.size(), 100);
for (float temp : temperatures) {
EXPECT_GE(temp, config_.temperature.min);
EXPECT_LE(temp, config_.temperature.max);
}
// Check that we got some variation
auto [min, max] = std::minmax_element(
temperatures.begin(), temperatures.end());
EXPECT_GT(*max - *min, 1.0f);
}
TEST_F(MockDeviceTest, ResponseDelay) {
// Configure delay
config_.responseDelay = 100ms;
device_->updateConfig(config_);
auto request = createTempRequest();
auto start = std::chrono::steady_clock::now();
stdexec::sync_wait(device_->sendMessage(
request,
[this](auto response) {
lastResponse_ = std::vector<uint8_t>(
response.begin(), response.end());
responseReceived_ = true;
}));
auto duration = std::chrono::steady_clock::now() - start;
EXPECT_GE(duration, config_.responseDelay);
}
TEST_F(MockDeviceTest, SimulatedErrors) {
// Configure high error rate
config_.simulateErrors = true;
config_.errorRate = 1.0f;
device_->updateConfig(config_);
auto request = createTempRequest();
EXPECT_THROW(
stdexec::sync_wait(device_->sendMessage(
request,
[](auto) {})),
std::runtime_error);
}
TEST_F(MockDeviceTest, FixedResponse) {
// Configure fixed response
std::vector<uint8_t> fixedResponse = {0x01, 0x02, 0x03};
config_.fixedResponse = fixedResponse;
device_->updateConfig(config_);
auto request = createTempRequest();
stdexec::sync_wait(device_->sendMessage(
request,
[this](auto response) {
lastResponse_ = std::vector<uint8_t>(
response.begin(), response.end());
responseReceived_ = true;
}));
ASSERT_TRUE(responseReceived_);
EXPECT_EQ(lastResponse_, fixedResponse);
}
TEST_F(MockDeviceTest, UnknownMessage) {
// Send unknown message type
std::vector<uint8_t> request = {0xFF, 0xFF, 0xFF};
stdexec::sync_wait(device_->sendMessage(
request,
[this](auto response) {
lastResponse_ = std::vector<uint8_t>(
response.begin(), response.end());
responseReceived_ = true;
}));
ASSERT_TRUE(responseReceived_);
EXPECT_EQ(lastResponse_, request); // Should echo unknown messages
}
TEST_F(MockDeviceTest, ConfigUpdate) {
// Update configuration
config_.temperature.min = 90.0f;
config_.temperature.max = 100.0f;
device_->updateConfig(config_);
auto request = createTempRequest();
stdexec::sync_wait(device_->sendMessage(
request,
[this](auto response) {
lastResponse_ = std::vector<uint8_t>(
response.begin(), response.end());
responseReceived_ = true;
}));
ASSERT_TRUE(responseReceived_);
verifyTempResponse(lastResponse_);
}