blob: 6bef6d395c06e0630381d520cf4a1aba1554d7bf [file] [edit]
/*
* SPDX-FileCopyrightText: Copyright OpenBMC Authors
* SPDX-License-Identifier: Apache-2.0
*/
#include "DbusMockTestBase.hpp"
#include "LoggingStub.hpp"
#include "NvidiaEventReporting.hpp"
#include "NvidiaGpuResetRequired.hpp"
#include <chrono>
#include <cstdint>
#include <memory>
#include <span>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
namespace
{
constexpr const char* criticalLevel =
"xyz.openbmc_project.Logging.Entry.Level.Critical";
// Long enough to cover the self-directed D-Bus round trip the fixture pumps.
constexpr std::chrono::seconds pumpTimeout{5};
} // namespace
class NvidiaGpuResetRequiredTest : public DbusMockTestBase
{
protected:
void SetUp() override
{
DbusMockTestBase::SetUp();
if (testing::Test::IsSkipped())
{
return;
}
// Share the single Logging.Create stub with every other fixture: the
// well-known name and the object path can each be claimed only once on
// the connection that every test shares.
ASSERT_TRUE(logging_stub::ensure(bus(), objects()));
logging_stub::setActiveCall(&createCall);
}
void TearDown() override
{
logging_stub::setActiveCall(nullptr);
DbusMockTestBase::TearDown();
}
logging_stub::CreateCall createCall;
};
// The Reset Required event carries no payload; the handler must create a
// critical phosphor-logging entry that names the resource requiring the reset.
TEST_F(NvidiaGpuResetRequiredTest, ResetRequiredEventCreatesCriticalLog)
{
auto handler =
std::make_shared<NvidiaResetRequiredEventHandler>("GPU_0", bus());
const EventInfo eventInfo{};
handler->handleResetRequiredEvent(eventInfo, std::span<const uint8_t>{});
ASSERT_TRUE(
pumpIoUntil([this] { return createCall.count > 0; }, pumpTimeout));
EXPECT_EQ(createCall.count, 1);
EXPECT_THAT(createCall.message, testing::HasSubstr("GPU_0"));
EXPECT_THAT(createCall.message, testing::HasSubstr("requires a reset"));
EXPECT_EQ(createCall.severity, criticalLevel);
EXPECT_TRUE(createCall.additionalData.empty());
}
// Dropping the handler before the async Create reply is processed must not
// crash: the completion callback holds only a weak_ptr and has to no-op once
// the handler is gone.
TEST_F(NvidiaGpuResetRequiredTest, HandlerDestroyedBeforeReplyIsSafe)
{
auto handler =
std::make_shared<NvidiaResetRequiredEventHandler>("GPU_3", bus());
const EventInfo eventInfo{};
handler->handleResetRequiredEvent(eventInfo, std::span<const uint8_t>{});
handler.reset();
// The request is already dispatched, so the stub still records it while the
// now-expired completion callback drains harmlessly.
ASSERT_TRUE(
pumpIoUntil([this] { return createCall.count > 0; }, pumpTimeout));
EXPECT_EQ(createCall.count, 1);
// The stub has recorded the request, but the reply that releases the
// pending async_send has not been delivered yet.
drainPendingAsync();
}