* -------------------------------------------------------------------------
* This file is part of the MindStudio project.
* Copyright (c) 2026 Huawei Technologies Co.,Ltd.
*
* MindStudio is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan
* PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
* NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. See the
* Mulan PSL v2 for more details.
* -------------------------------------------------------------------------
*/
#include <gtest/gtest.h>
#include "DataBaseManager.h"
#include "MemSnapshotDatabase.h"
#include "MemSnapshotDefs.h"
#include "MemSnapshotTableColumn.h"
#include "MemSnapshotParser.h"
#include "FileUtil.h"
#include "StringUtil.h"
#include "../TestSuit.h"
using namespace Dic::Module::Timeline;
using namespace Dic::Module::FullDb;
using namespace Dic::Module::MemSnapshot;
using namespace Dic;
class MemSnapshotDatabaseTest : public ::testing::Test {
public:
static void SetUpTestSuite() {
testDbPath = TestSuit::GetTestDataFile("snapshot", "snapshot_with_multi_devices.pkl.db");
snapshotDb = DataBaseManager::Instance().GetMemSnapshotDatabase(testDbPath);
ASSERT_TRUE(snapshotDb != nullptr);
ASSERT_TRUE(snapshotDb->OpenDbReadOnly(testDbPath));
}
static void TearDownTestSuite() {
if (snapshotDb != nullptr) {
snapshotDb->CloseDb();
}
DataBaseManager::Instance().Clear(DatabaseType::MEM_SNAPSHOT);
}
protected:
static std::string testDbPath;
static std::shared_ptr<MemSnapshotDatabase> snapshotDb;
};
std::string MemSnapshotDatabaseTest::testDbPath;
std::shared_ptr<MemSnapshotDatabase> MemSnapshotDatabaseTest::snapshotDb = nullptr;
TEST_F(MemSnapshotDatabaseTest, OpenAndCloseDb) {
EXPECT_TRUE(snapshotDb->IsOpen());
EXPECT_TRUE(snapshotDb->OpenDbReadOnly(testDbPath));
snapshotDb->CloseDb();
EXPECT_FALSE(snapshotDb->IsOpen());
EXPECT_TRUE(snapshotDb->OpenDbReadOnly(testDbPath));
EXPECT_TRUE(snapshotDb->IsOpen());
}
TEST_F(MemSnapshotDatabaseTest, CheckAllTableExist) { EXPECT_TRUE(snapshotDb->CheckAllTableExist()); }
TEST_F(MemSnapshotDatabaseTest, CheckInitDevices) {
const auto deviceIds = snapshotDb->GetDeviceIds();
EXPECT_EQ(deviceIds.size(), 2);
if (deviceIds.size() == 2) {
EXPECT_EQ(deviceIds[0], "0");
EXPECT_EQ(deviceIds[1], "1");
}
EXPECT_EQ(snapshotDb->GetDeviceMaxEntryId("0"), 8131);
EXPECT_EQ(snapshotDb->GetDeviceMaxEntryId("1"), 9699);
}
TEST_F(MemSnapshotDatabaseTest, QueryAllBlocks) {
std::vector<Block> blocks;
bool result = snapshotDb->QueryAllBlocks(blocks, "0");
EXPECT_TRUE(result);
EXPECT_EQ(blocks.size(), 3219);
result = snapshotDb->QueryAllBlocks(blocks, "1");
EXPECT_TRUE(result);
EXPECT_EQ(blocks.size(), 6435);
}
TEST_F(MemSnapshotDatabaseTest, QueryBlockById) {
const auto expectBlockId = 1;
auto block = snapshotDb->QueryBlockById(expectBlockId, "0");
EXPECT_TRUE(block.has_value());
EXPECT_EQ(block->id, expectBlockId);
EXPECT_EQ(block->size, 41943552);
EXPECT_EQ(block->state, BLOCK_STATE_ACTIVE_ALLOC);
block = snapshotDb->QueryBlockById(expectBlockId, "1");
EXPECT_TRUE(block.has_value());
EXPECT_EQ(block->id, expectBlockId);
EXPECT_EQ(block->size, 37888);
EXPECT_EQ(block->state, BLOCK_STATE_ACTIVE_ALLOC);
auto nonExistentBlock = snapshotDb->QueryBlockById(-1000, "0");
EXPECT_FALSE(nonExistentBlock.has_value());
nonExistentBlock = snapshotDb->QueryBlockById(-1000, "1");
EXPECT_FALSE(nonExistentBlock.has_value());
}
TEST_F(MemSnapshotDatabaseTest, GetRealValueInTableDictionaryMap) {
std::string realValue = snapshotDb->GetRealValueInTableDictionaryMap("block", "state", 1);
std::string nonExistentTableValue = snapshotDb->GetRealValueInTableDictionaryMap("non_existent_table", "state", 1);
EXPECT_EQ(nonExistentTableValue, "1");
std::string nonExistentColumnValue =
snapshotDb->GetRealValueInTableDictionaryMap("block", "non_existent_column", 1);
EXPECT_EQ(nonExistentColumnValue, "1");
std::string nonExistentKeyValue = snapshotDb->GetRealValueInTableDictionaryMap("block", "state", 9999);
EXPECT_EQ(nonExistentKeyValue, "9999");
}
TEST_F(MemSnapshotDatabaseTest, Reset) {
MemSnapshotDatabase::Reset();
EXPECT_FALSE(snapshotDb->IsOpen());
snapshotDb = DataBaseManager::Instance().GetMemSnapshotDatabase(testDbPath);
ASSERT_TRUE(snapshotDb != nullptr);
EXPECT_TRUE(snapshotDb->OpenDbReadOnly(testDbPath));
}
TEST_F(MemSnapshotDatabaseTest, QueryMemoryRecords) {
MemSnapshotAllocationParams params;
params.deviceId = "0";
params.eventType = "BLOCK";
std::vector<MemoryRecord> records;
snapshotDb->QueryMemoryRecords(params, records);
EXPECT_EQ(records.size(), 8132);
if (!records.empty()) {
EXPECT_EQ(records[0].id, 0);
EXPECT_EQ(records[0].allocated, 94482944);
EXPECT_EQ(records[0].reserved, 155189248);
EXPECT_EQ(records[0].active, 94482944);
}
size_t checkIdx = 1000;
while (checkIdx < records.size()) {
EXPECT_LE(records[checkIdx].allocated, records[checkIdx].active);
EXPECT_LE(records[checkIdx].active, records[checkIdx].reserved);
checkIdx += 1000;
}
}
TEST_F(MemSnapshotDatabaseTest, QueryBlocksTable) {
MemSnapshotBlockParams params;
params.deviceId = "0";
params.eventType = "BLOCK";
params.currentPage = 1;
params.pageSize = 10;
params.orderBy = "id";
std::vector<BlockTableItemDTO> blocks;
int64_t totalCount = snapshotDb->QueryBlocksTable(params, blocks);
EXPECT_EQ(totalCount, 3219);
EXPECT_EQ(blocks.size(), 10);
if (!blocks.empty()) {
EXPECT_EQ(blocks[0].id, -320);
EXPECT_EQ(blocks[0].address, 20697531023360);
EXPECT_EQ(blocks[0].size, 4096.5);
EXPECT_EQ(blocks[0].requestedSize, 4096);
EXPECT_EQ(blocks[blocks.size() - 1].id, -311);
EXPECT_EQ(blocks[blocks.size() - 1].address, 20697475301376);
EXPECT_EQ(blocks[blocks.size() - 1].size, 2048.5);
EXPECT_EQ(blocks[blocks.size() - 1].requestedSize, 2048);
}
}
TEST_F(MemSnapshotDatabaseTest, QueryBlocksTableWithEventIdxRange) {
MemSnapshotBlockParams params;
params.deviceId = "0";
params.eventType = "BLOCK";
params.currentPage = 1;
params.pageSize = 10;
params.startEventIdx = 100;
params.endEventIdx = 1000;
params.orderBy = "allocEventId";
std::vector<BlockTableItemDTO> blocks;
int64_t totalCount = snapshotDb->QueryBlocksTable(params, blocks);
EXPECT_EQ(totalCount, 764);
EXPECT_EQ(blocks.size(), 10);
for (const auto &block : blocks) {
EXPECT_TRUE((block.allocEventId < 0 || static_cast<uint64_t>(block.allocEventId) >= params.endEventIdx) &&
(block.freeEventId < 0 || static_cast<uint64_t>(block.freeEventId) >= params.startEventIdx));
}
}
TEST_F(MemSnapshotDatabaseTest, QueryBlocksTableWithFilters) {
MemSnapshotBlockParams params;
params.deviceId = "0";
params.eventType = "BLOCK";
params.currentPage = 1;
params.pageSize = 10;
params.orderBy = "id";
params.filters["state"] = "allocated";
std::vector<BlockTableItemDTO> blocks;
int64_t totalCount = snapshotDb->QueryBlocksTable(params, blocks);
EXPECT_EQ(totalCount, 3219);
EXPECT_EQ(blocks.size(), params.pageSize);
for (const auto &block : blocks) {
EXPECT_EQ(block.state, BLOCK_STATE_ACTIVE_ALLOC);
}
}
TEST_F(MemSnapshotDatabaseTest, QueryBlocksTableWithDescOrder) {
MemSnapshotBlockParams params;
params.deviceId = "0";
params.eventType = "BLOCK";
params.currentPage = 1;
params.pageSize = 10;
params.orderBy = BlockTableColumn::ADDRESS;
params.desc = true;
std::vector<BlockTableItemDTO> blocks;
int64_t totalCount = snapshotDb->QueryBlocksTable(params, blocks);
EXPECT_EQ(totalCount, 3219);
EXPECT_EQ(blocks.size(), params.pageSize);
for (size_t i = 1; i < blocks.size(); ++i) {
EXPECT_GE(blocks[i - 1].address, blocks[i].address);
}
}
TEST_F(MemSnapshotDatabaseTest, QueryBlocksTableOnlyUnreleasedInRange) {
MemSnapshotBlockParams params;
params.deviceId = "0";
params.eventType = "BLOCK";
params.currentPage = 1;
params.pageSize = 10;
params.startEventIdx = 100;
params.endEventIdx = 1000;
params.orderBy = "allocEventId";
params.onlyUnreleasedInRange = true;
std::vector<BlockTableItemDTO> blocks;
int64_t totalCount = snapshotDb->QueryBlocksTable(params, blocks);
EXPECT_EQ(totalCount, 146);
ASSERT_EQ(blocks.size(), params.pageSize);
for (const auto &block : blocks) {
EXPECT_GE(block.allocEventId, params.startEventIdx);
EXPECT_LE(block.allocEventId, params.endEventIdx);
EXPECT_TRUE(block.freeEventId < 0 || static_cast<uint64_t>(block.freeEventId) > params.endEventIdx);
}
}
TEST_F(MemSnapshotDatabaseTest, QueryBlocksTableOnlyUnreleasedInRangeWithFilters) {
MemSnapshotBlockParams params;
params.deviceId = "0";
params.eventType = "BLOCK";
params.currentPage = 1;
params.pageSize = 10;
params.startEventIdx = 100;
params.endEventIdx = 1000;
params.orderBy = "allocEventId";
params.onlyUnreleasedInRange = true;
params.filters["state"] = BLOCK_STATE_ACTIVE_ALLOC;
params.rangeFilters["allocEventId"] = {100, 500};
std::vector<BlockTableItemDTO> blocks;
int64_t totalCount = snapshotDb->QueryBlocksTable(params, blocks);
EXPECT_EQ(totalCount, 78);
ASSERT_EQ(blocks.size(), params.pageSize);
for (const auto &block : blocks) {
EXPECT_EQ(block.state, BLOCK_STATE_ACTIVE_ALLOC);
EXPECT_GE(block.allocEventId, 100);
EXPECT_LE(block.allocEventId, 500);
EXPECT_TRUE(block.freeEventId < 0 || static_cast<uint64_t>(block.freeEventId) > params.endEventIdx);
}
}
TEST_F(MemSnapshotDatabaseTest, QueryPotentialLeakStats) {
MemSnapshotLeakStatsParams params;
params.deviceId = "0";
params.startEventIdx = 100;
params.endEventIdx = 1000;
MemSnapshotLeakStatsDTO stats;
EXPECT_TRUE(snapshotDb->QueryPotentialLeakStats(params, stats));
EXPECT_EQ(stats.totalSize, 108473.0);
EXPECT_EQ(stats.maxSize, 9216.5);
EXPECT_EQ(stats.minSize, 0.5);
}
TEST_F(MemSnapshotDatabaseTest, QueryPotentialLeakStatsWithoutMatches) {
MemSnapshotLeakStatsParams params;
params.deviceId = "0";
params.startEventIdx = 0;
params.endEventIdx = 0;
MemSnapshotLeakStatsDTO stats;
EXPECT_TRUE(snapshotDb->QueryPotentialLeakStats(params, stats));
EXPECT_EQ(stats.totalSize, 0);
EXPECT_EQ(stats.maxSize, 0);
EXPECT_EQ(stats.minSize, 0);
}
TEST_F(MemSnapshotDatabaseTest, QueryTraceEntriesTable) {
MemSnapshotEventParams params;
params.deviceId = "0";
params.currentPage = 1;
params.pageSize = 10;
params.orderBy = TraceEntryTableColumn::ID;
std::vector<TraceEntryTableItemDTO> entries;
int64_t totalCount = snapshotDb->QueryTraceEntriesTable(params, entries);
EXPECT_EQ(totalCount, 8132);
EXPECT_EQ(entries.size(), params.pageSize);
if (!entries.empty()) {
EXPECT_EQ(entries[0].id, 0);
EXPECT_EQ(entries[0].action, TRACE_ENTRY_ACTION_SEG_MAP);
EXPECT_EQ(entries[0].address, 20697552257024);
}
}
TEST_F(MemSnapshotDatabaseTest, QueryTraceEntriesTableWithEventIdxRange) {
MemSnapshotEventParams params;
params.deviceId = "0";
params.currentPage = 1;
params.pageSize = 15;
params.startEventIdx = 100;
params.endEventIdx = 500;
params.orderBy = TraceEntryTableColumn::ID;
std::vector<TraceEntryTableItemDTO> entries;
int64_t totalCount = snapshotDb->QueryTraceEntriesTable(params, entries);
EXPECT_EQ(totalCount, 401);
EXPECT_EQ(entries.size(), params.pageSize);
for (const auto &entry : entries) {
EXPECT_GE(entry.id, params.startEventIdx);
EXPECT_LE(entry.id, params.endEventIdx);
}
}
TEST_F(MemSnapshotDatabaseTest, QueryTraceEntriesTableWithFilters) {
MemSnapshotEventParams params;
params.deviceId = "0";
params.currentPage = 1;
params.pageSize = 10;
params.orderBy = "id";
params.filters["action"] = "alloc";
std::vector<TraceEntryTableItemDTO> entries;
int64_t totalCount = snapshotDb->QueryTraceEntriesTable(params, entries);
EXPECT_EQ(totalCount, 2899);
EXPECT_EQ(entries.size(), params.pageSize);
for (const auto &entry : entries) {
EXPECT_EQ(entry.action, TRACE_ENTRY_ACTION_ALLOC);
}
}
TEST_F(MemSnapshotDatabaseTest, QueryTraceEntriesTableWithAscOrder) {
MemSnapshotEventParams params;
params.deviceId = "0";
params.currentPage = 1;
params.pageSize = 10;
params.orderBy = TraceEntryTableColumn::ADDRESS;
params.desc = false;
std::vector<TraceEntryTableItemDTO> entries;
int64_t totalCount = snapshotDb->QueryTraceEntriesTable(params, entries);
EXPECT_EQ(totalCount, 8132);
EXPECT_EQ(entries.size(), params.pageSize);
for (size_t i = 1; i < entries.size(); ++i) {
EXPECT_LE(entries[i - 1].address, entries[i].address);
}
}
TEST_F(MemSnapshotDatabaseTest, QueryTraceEntriesTableSecondPage) {
MemSnapshotEventParams params;
params.deviceId = "0";
params.currentPage = 10;
params.pageSize = 100;
params.orderBy = TraceEntryTableColumn::RESERVED;
std::vector<TraceEntryTableItemDTO> entries;
int64_t totalCount = snapshotDb->QueryTraceEntriesTable(params, entries);
EXPECT_EQ(totalCount, 8132);
EXPECT_EQ(entries.size(), params.pageSize);
for (size_t i = 1; i < entries.size(); ++i) {
EXPECT_LE(entries[i - 1].reserved, entries[i].reserved);
}
}
TEST_F(MemSnapshotDatabaseTest, QueryTraceEntryById) {
const auto expectEntryId = 1;
const auto entry = snapshotDb->QueryTraceEntryById(expectEntryId, "0");
EXPECT_TRUE(entry.has_value());
EXPECT_EQ(entry->id, expectEntryId);
auto nonExistentEntry = snapshotDb->QueryTraceEntryById(-1000, "0");
EXPECT_FALSE(nonExistentEntry.has_value());
nonExistentEntry = snapshotDb->QueryTraceEntryById(-1000, "1");
EXPECT_FALSE(nonExistentEntry.has_value());
}
TEST_F(MemSnapshotDatabaseTest, QueryFreeRequestedTraceEntryByBlock) {
MemSnapshotBlockParams params;
params.deviceId = "0";
params.eventType = "BLOCK";
params.currentPage = 1;
params.pageSize = 100;
params.orderBy = "id";
std::vector<BlockTableItemDTO> blocks;
snapshotDb->QueryBlocksTable(params, blocks);
bool foundBlockWithFree = false;
for (const auto &block : blocks) {
if (block.freeEventId > 0) {
foundBlockWithFree = true;
Block tmpBlock{.address = block.address, .allocEventId = block.allocEventId};
auto freeRequestedEntry = snapshotDb->QueryFreeRequestedTraceEntryByBlock(tmpBlock, "0");
if (freeRequestedEntry.has_value()) {
EXPECT_GT(freeRequestedEntry->id, block.allocEventId);
EXPECT_EQ(freeRequestedEntry->address, block.address);
}
break;
}
}
EXPECT_TRUE(foundBlockWithFree || !blocks.empty());
}
TEST_F(MemSnapshotDatabaseTest, QueryBlocksTableWithSizeRange) {
MemSnapshotBlockParams params;
params.deviceId = "0";
params.eventType = "BLOCK";
params.currentPage = 1;
params.pageSize = 10;
params.orderBy = "size";
params.minSize = 1024;
params.maxSize = 1048576;
std::vector<BlockTableItemDTO> blocks;
int64_t totalCount = snapshotDb->QueryBlocksTable(params, blocks);
EXPECT_GT(totalCount, 0);
EXPECT_LE(blocks.size(), params.pageSize);
for (const auto &block : blocks) {
EXPECT_GE(block.size, params.minSize / 1024);
EXPECT_LE(block.size, params.maxSize / 1024);
}
}
TEST_F(MemSnapshotDatabaseTest, QueryBlocksTableWithRangeFilters) {
MemSnapshotBlockParams params;
params.deviceId = "0";
params.eventType = "BLOCK";
params.currentPage = 1;
params.pageSize = 10;
params.orderBy = "id";
params.rangeFilters["size"] = {1024, 1048576};
std::vector<BlockTableItemDTO> blocks;
int64_t totalCount = snapshotDb->QueryBlocksTable(params, blocks);
EXPECT_GT(totalCount, 0);
for (const auto &block : blocks) {
EXPECT_GE(block.size, 1024);
EXPECT_LE(block.size, 1048576);
}
}
TEST_F(MemSnapshotDatabaseTest, QueryBlocksTableWithMultipleFiltersCombined) {
MemSnapshotBlockParams params;
params.deviceId = "0";
params.eventType = "BLOCK";
params.currentPage = 1;
params.pageSize = 10;
params.orderBy = "size";
params.startEventIdx = 100;
params.endEventIdx = 5000;
params.filters["state"] = "allocated";
params.rangeFilters["allocEventId"] = {0, 9999999};
params.rangeFilters["freeEventId"] = {
-1, -1};
params.rangeFilters["size"] = {1024, 1024 * 1024};
std::vector<BlockTableItemDTO> blocks;
int64_t totalCount = snapshotDb->QueryBlocksTable(params, blocks);
EXPECT_GE(totalCount, 0);
EXPECT_EQ(blocks.size(), std::min(totalCount, params.pageSize));
double preBlockSize = 0;
for (const auto &block : blocks) {
EXPECT_GE(block.size, preBlockSize);
preBlockSize = block.size;
EXPECT_TRUE(block.allocEventId < 0 || static_cast<uint64_t>(block.allocEventId) <= params.endEventIdx);
EXPECT_TRUE(block.freeEventId < 0 || static_cast<uint64_t>(block.freeEventId) >= params.startEventIdx);
EXPECT_EQ(block.state, BLOCK_STATE_ACTIVE_ALLOC);
EXPECT_TRUE(0 <= block.allocEventId && static_cast<uint64_t>(block.allocEventId) <= 9999999);
EXPECT_EQ(block.freeEventId, -1);
EXPECT_TRUE(1024 <= block.size && block.size <= 1024 * 1024);
}
}
TEST_F(MemSnapshotDatabaseTest, QueryTraceEntriesTableWithRangeFilters) {
MemSnapshotEventParams params;
params.deviceId = "0";
params.currentPage = 1;
params.pageSize = 10;
params.orderBy = "id";
params.rangeFilters["size"] = {1024, 1048576};
std::vector<TraceEntryTableItemDTO> entries;
int64_t totalCount = snapshotDb->QueryTraceEntriesTable(params, entries);
EXPECT_GT(totalCount, 0);
for (const auto &entry : entries) {
EXPECT_GE(entry.size, 1024);
EXPECT_LE(entry.size, 1048576);
}
}
TEST_F(MemSnapshotDatabaseTest, QuerySegmentEventsUntil) {
const int64_t eventId = 1000;
std::vector<TraceEntry> events;
bool result = snapshotDb->QuerySegmentEventsUntil(eventId, "0", events);
EXPECT_TRUE(result);
EXPECT_GT(events.size(), 0);
for (const auto &event : events) {
EXPECT_TRUE(event.action == TRACE_ENTRY_ACTION_SEG_MAP || event.action == TRACE_ENTRY_ACTION_SEG_UNMAP ||
event.action == TRACE_ENTRY_ACTION_SEG_ALLOC || event.action == TRACE_ENTRY_ACTION_SEG_FREE);
}
}
TEST_F(MemSnapshotDatabaseTest, QuerySegmentEventsUntilMaxEventId) {
const int64_t maxEventId = snapshotDb->GetDeviceMaxEntryId("0");
std::vector<TraceEntry> events;
bool result = snapshotDb->QuerySegmentEventsUntil(maxEventId, "0", events);
EXPECT_TRUE(result);
for (const auto &event : events) {
EXPECT_LE(event.id, maxEventId);
}
}
TEST_F(MemSnapshotDatabaseTest, QueryActiveBlocksByEventId) {
const int64_t eventId = 1000;
std::vector<Block> blocks;
bool result = snapshotDb->QueryActiveBlocksByEventId(eventId, "0", blocks);
EXPECT_TRUE(result);
EXPECT_GT(blocks.size(), 0);
for (const auto &block : blocks) {
EXPECT_LE(block.allocEventId, eventId);
EXPECT_TRUE(block.freeEventId > eventId || block.freeEventId < 0);
}
}