数据库:下位机交互数据全量落库,SQLite 封装重构
- 新增 msg_log 原始帧表,RX/TX 双向记录原始字节与校验结果 - SQLite 封装改为描述符驱动的泛化 insert,删除 10 个手写 SQL - 新增 ccuSetParmCmd/ccuSetParmFb 表,补齐 CCU 参数设定反馈落库 - 错误防崩溃:统一加锁、fail-open 降级、损坏自动重建、析构顺序修复 - WAL/迁移/预编译语句路径,数据库路径支持 mission 配置 dbpath - 清理未使用的 shell.c/sqlite3ext.h/SQLite.zip
This commit is contained in:
@@ -30,6 +30,22 @@ static bool rawCount(const std::string& path, const std::string& table, long lon
|
||||
return rawQueryInt(path, "SELECT COUNT(*) FROM " + table, out);
|
||||
}
|
||||
|
||||
static bool rawQueryText(const std::string& path, const std::string& sql, std::string& out) {
|
||||
sqlite3* db = nullptr;
|
||||
if (sqlite3_open(path.c_str(), &db) != SQLITE_OK) return false;
|
||||
sqlite3_stmt* stmt = nullptr;
|
||||
bool ok = false;
|
||||
if (sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, nullptr) == SQLITE_OK) {
|
||||
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
const unsigned char* t = sqlite3_column_text(stmt, 0);
|
||||
if (t) { out = reinterpret_cast<const char*>(t); ok = true; }
|
||||
}
|
||||
}
|
||||
if (stmt) sqlite3_finalize(stmt);
|
||||
sqlite3_close(db);
|
||||
return ok;
|
||||
}
|
||||
|
||||
TEST(SqliteTest, InsertCcuStateReadBack)
|
||||
{
|
||||
std::string path = tmpPath("ccu");
|
||||
@@ -147,3 +163,93 @@ TEST(SqliteTest, MultipleInsertsCount)
|
||||
EXPECT_EQ(n, 3);
|
||||
std::remove(path.c_str());
|
||||
}
|
||||
|
||||
TEST(SqliteTest, InsertCcuSetParmCmdReadBack)
|
||||
{
|
||||
std::string path = tmpPath("setparmcmd");
|
||||
{
|
||||
SQLite db(path); ASSERT_TRUE(db.createTable());
|
||||
ccuSetParmCmd c{}; c.fcuToInsLimit1 = 7; c.powerSocHold2 = 88;
|
||||
EXPECT_TRUE(db.insertData(c));
|
||||
}
|
||||
long long v = 0;
|
||||
EXPECT_TRUE(rawQueryInt(path, "SELECT fcuToInsLimit1 FROM ccuSetParmCmd", v));
|
||||
EXPECT_EQ(v, 7);
|
||||
EXPECT_TRUE(rawQueryInt(path, "SELECT powerSocHold2 FROM ccuSetParmCmd", v));
|
||||
EXPECT_EQ(v, 88);
|
||||
std::remove(path.c_str());
|
||||
}
|
||||
|
||||
TEST(SqliteTest, InsertCcuSetParmFbReadBack)
|
||||
{
|
||||
std::string path = tmpPath("setparmfb");
|
||||
{
|
||||
SQLite db(path); ASSERT_TRUE(db.createTable());
|
||||
msg_CcuSetParmFbMsg fb{}; fb.flag = 1; fb.failureCode = 2;
|
||||
EXPECT_TRUE(db.insertData(fb));
|
||||
}
|
||||
long long v = 0;
|
||||
EXPECT_TRUE(rawQueryInt(path, "SELECT flag FROM ccuSetParmFb", v));
|
||||
EXPECT_EQ(v, 1);
|
||||
EXPECT_TRUE(rawQueryInt(path, "SELECT failureCode FROM ccuSetParmFb", v));
|
||||
EXPECT_EQ(v, 2);
|
||||
std::remove(path.c_str());
|
||||
}
|
||||
|
||||
TEST(SqliteTest, LogRawFrameReadBack)
|
||||
{
|
||||
std::string path = tmpPath("raw");
|
||||
{
|
||||
SQLite db(path); ASSERT_TRUE(db.createTable());
|
||||
const unsigned char frame[] = {0x20, 0x20, 0x51, 0x00, 0x01, 0x02, 0x03};
|
||||
db.onFrame(0, 0x0051, "ccuState", frame, sizeof(frame), true);
|
||||
db.onFrame(1, 0x0001, "disHighVolBusCmd", frame, sizeof(frame), true);
|
||||
}
|
||||
long long n = 0;
|
||||
EXPECT_TRUE(rawCount(path, "msg_log", n));
|
||||
EXPECT_EQ(n, 2);
|
||||
std::string hex;
|
||||
EXPECT_TRUE(rawQueryText(path, "SELECT payload_hex FROM msg_log ORDER BY id LIMIT 1", hex));
|
||||
EXPECT_EQ(hex, "20205100010203");
|
||||
long long dir = 0;
|
||||
EXPECT_TRUE(rawQueryInt(path, "SELECT direction FROM msg_log ORDER BY id DESC LIMIT 1", dir));
|
||||
EXPECT_EQ(dir, 1);
|
||||
std::remove(path.c_str());
|
||||
}
|
||||
|
||||
TEST(SqliteTest, InvalidPathIsFailOpen)
|
||||
{
|
||||
SQLite db("/invalid/path/nonexistent_dir/test.db");
|
||||
EXPECT_EQ(db.status(), SQLite::Status::Disabled);
|
||||
EXPECT_FALSE(db.isConnected());
|
||||
ccuState c{}; c.ins_soc = 1;
|
||||
EXPECT_FALSE(db.insertData(c)); // 不抛异常,返回 false
|
||||
ccuColCmd cmd{};
|
||||
EXPECT_FALSE(db.insertData(cmd));
|
||||
const unsigned char frame[] = {0x20, 0x20};
|
||||
db.onFrame(0, 0x0051, "ccuState", frame, sizeof(frame), true); // 不崩溃
|
||||
}
|
||||
|
||||
TEST(SqliteTest, CorruptDatabaseRecovered)
|
||||
{
|
||||
std::string path = tmpPath("corrupt");
|
||||
{
|
||||
// 写入非 SQLite 内容,模拟损坏的库文件
|
||||
FILE* f = fopen(path.c_str(), "wb");
|
||||
ASSERT_TRUE(f != nullptr);
|
||||
for (int i = 0; i < 4096; ++i) fputc((i * 7 + 3) & 0xFF, f);
|
||||
fclose(f);
|
||||
|
||||
SQLite db(path);
|
||||
// 应能备份损坏文件并重建,恢复可用
|
||||
EXPECT_EQ(db.status(), SQLite::Status::OK);
|
||||
EXPECT_TRUE(db.isConnected());
|
||||
ccuState c{}; c.ins_soc = 99;
|
||||
EXPECT_TRUE(db.insertData(c));
|
||||
}
|
||||
long long v = 0;
|
||||
EXPECT_TRUE(rawQueryInt(path, "SELECT ins_soc FROM ccuState", v));
|
||||
EXPECT_EQ(v, 99);
|
||||
std::remove(path.c_str());
|
||||
std::remove((path + ".corrupt").c_str());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user