TDengine/source/dnode/mnode/impl/test/xnode/xnodeEncodeDecodeTest.cpp

415 lines
13 KiB
C++
Raw Normal View History

feat(taosx): support distributed taosx (#34126) * feat: add xnode syntax * refactor(xnode): reduce function complexity * chore: add lost xnode.h file * feat(xnode): create xnode task * chore: fix double free error * add xnoded * start xnoded as subprocess * complete xnode task feature * complete show xnode jobs feature * complete with option feature * complete alter xnode job feature * complete alter xnode task feature * complete user pass feature * clean code * modify status type as char * fix leader ep null * fix start task req null * fix pass id for status * support timeout msg * drop xnode task relative jobs * clean code * wip * chore: add test cases for xnode * chore: fix 3.0 merge changes * fix drain core dump and create task core dump * add password check * retrieve xnode status from xnoded * pass integer as double to cjson * add some debug log * add some job log * fix start task lock * do not handle http response * fix coredump drop xnode task by name * support start/stop/drop task by name * remove mock xnoded * support unix socket * kill pre-xnoded before start * support dnode close xnoded * test(xnode): add unit test cases for xnode * rebalance support where clause * fix some test issue * unformat http post content json string * add xnode zh doc * modify drain description * remove job create/stop/drop operation * support rebalance all without where condition * support alter task by name * add NULL param for mndCheckOperPrivilege * add xnode txnode module for libmnode.a * code clean * change parser len to 4096 * clean code * chore: try to fix gtest/gtest.h not found * chore: fix markdown files * chore: fix markdown in zh * chore: fix enum issue and add ci * chore: fix test case problem * chore: fix pKeyVal overflow * chore: rename to 排空节点 * chore: external cmake remove parallel * chore: add DEP_ext_gtest for xnode test * chore: fix gtest errors * chore: remove gtest pthread lib * chore: fix data type not match * chore: fix some lint errors * chore: fix void unlink * chore: fix return with null pointer check * chore: fix pointer double free and xnodeMemoryTest strncpy null * chore: fix xnode encode action invalid datelen * chore: remove TD_LINUX condition * chore: use PRIu64 denote long long * chore: fix task parser NULL and allow no with clause * fix(xnode): fix windows build error * chore: fix windows curl error * chore: fix test case ins_tables relative error * chore: fix memory leak * docs: update taosx docs * chore: update taosx docs * chore: add role priviledge table * chore: fix error code doc * chore: fix test_xnode.py * chore: fix doc typo * fix: ci error while run test_user_privilege_sysinfo.py --------- Co-authored-by: Linhe Huo <linhehuo@gmail.com> Co-authored-by: huohong <sallyhuo@taosdata.com> Co-authored-by: Simon Guan <guanshengliang@qq.com>
2026-01-01 06:51:03 +00:00
/**
* @file xnodeEncodeDecodeTest.cpp
* @brief XNode metadata encode/decode unit tests
* @version 1.0
* @date 2025-12-25
*/
#include <gtest/gtest.h>
#include "sdb.h"
#include "tdef.h"
#include "tglobal.h"
// Simplified XNode structures for testing
typedef struct SXnodeObj {
int32_t id;
int32_t urlLen;
char *url;
int32_t statusLen;
char *status;
int64_t createTime;
int64_t updateTime;
} SXnodeObj;
class MndTestXnodeEncodeDecode : public ::testing::Test {
protected:
static void SetUpTestSuite() {
dDebugFlag = 143;
mDebugFlag = 143;
tsLogEmbedded = 1;
tsAsyncLog = 0;
const char *path = TD_TMP_DIR_PATH "td_xnode_test";
taosRemoveDir(path);
taosMkDir(path);
tstrncpy(tsLogDir, path, PATH_MAX);
if (taosInitLog("xnode_test_log", 1, false) != 0) {
printf("failed to init log file\n");
}
}
static void TearDownTestSuite() { taosCloseLog(); }
public:
void SetUp() override {}
void TearDown() override {}
};
// Helper function to compare XNode objects
bool compareXnodeObj(SXnodeObj *obj1, SXnodeObj *obj2) {
if (obj1->id != obj2->id) return false;
if (obj1->urlLen != obj2->urlLen) return false;
if (obj1->statusLen != obj2->statusLen) return false;
if (obj1->urlLen > 0 && memcmp(obj1->url, obj2->url, obj1->urlLen) != 0) return false;
if (obj1->statusLen > 0 && memcmp(obj1->status, obj2->status, obj1->statusLen) != 0) return false;
if (obj1->createTime != obj2->createTime) return false;
if (obj1->updateTime != obj2->updateTime) return false;
return true;
}
TEST_F(MndTestXnodeEncodeDecode, test_xnode_encode_decode) {
// Create a test XNode object
SXnodeObj obj = {0};
obj.id = 1;
obj.urlLen = strlen("xnode1:6050") + 1;
obj.url = (char *)taosMemoryCalloc(obj.urlLen, 1);
strcpy(obj.url, "xnode1:6050");
obj.statusLen = strlen("online") + 1;
obj.status = (char *)taosMemoryCalloc(obj.statusLen, 1);
strcpy(obj.status, "online");
obj.createTime = 1234567890;
obj.updateTime = 1234567900;
// Encode the object (using mndXnodeActionEncode from mndXnode.c)
// Note: We need to access the internal encode function
// For now, we'll test the encode/decode logic separately
// Since we don't have direct access to encode function, we test the raw format
int32_t rawDataLen = sizeof(SXnodeObj) + 64 + obj.urlLen;
SSdbRaw *pRaw = sdbAllocRaw(SDB_XNODE, 1, rawDataLen);
ASSERT_NE(pRaw, nullptr);
int32_t dataPos = 0;
sdbSetRawInt32(pRaw, dataPos, obj.id);
dataPos += sizeof(obj.id);
sdbSetRawInt32(pRaw, dataPos, obj.urlLen);
dataPos += sizeof(obj.urlLen);
sdbSetRawBinary(pRaw, dataPos, obj.url, obj.urlLen);
dataPos += obj.urlLen;
sdbSetRawInt32(pRaw, dataPos, obj.statusLen);
dataPos += sizeof(obj.statusLen);
sdbSetRawBinary(pRaw, dataPos, obj.status, obj.statusLen);
dataPos += obj.statusLen;
sdbSetRawInt64(pRaw, dataPos, obj.createTime);
dataPos += sizeof(obj.createTime);
sdbSetRawInt64(pRaw, dataPos, obj.updateTime);
dataPos += sizeof(obj.updateTime);
sdbSetRawDataLen(pRaw, dataPos);
// Decode the raw data
int8_t sver = 0;
ASSERT_EQ(sdbGetRawSoftVer(pRaw, &sver), 0);
ASSERT_EQ(sver, 1);
SSdbRow *pRow = sdbAllocRow(sizeof(SXnodeObj));
ASSERT_NE(pRow, nullptr);
SXnodeObj *pDecoded = (SXnodeObj *)sdbGetRowObj(pRow);
ASSERT_NE(pDecoded, nullptr);
// Reset dataPos for decoding
dataPos = 0;
sdbGetRawInt32(pRaw, dataPos, &pDecoded->id);
dataPos += sizeof(pDecoded->id);
sdbGetRawInt32(pRaw, dataPos, &pDecoded->urlLen);
dataPos += sizeof(pDecoded->urlLen);
if (pDecoded->urlLen > 0) {
pDecoded->url = (char *)taosMemoryCalloc(pDecoded->urlLen, 1);
sdbGetRawBinary(pRaw, dataPos, pDecoded->url, pDecoded->urlLen);
dataPos += pDecoded->urlLen;
}
sdbGetRawInt32(pRaw, dataPos, &pDecoded->statusLen);
dataPos += sizeof(pDecoded->statusLen);
if (pDecoded->statusLen > 0) {
pDecoded->status = (char *)taosMemoryCalloc(pDecoded->statusLen, 1);
sdbGetRawBinary(pRaw, dataPos, pDecoded->status, pDecoded->statusLen);
dataPos += pDecoded->statusLen;
}
sdbGetRawInt64(pRaw, dataPos, &pDecoded->createTime);
dataPos += sizeof(pDecoded->createTime);
sdbGetRawInt64(pRaw, dataPos, &pDecoded->updateTime);
dataPos += sizeof(pDecoded->updateTime);
// Verify decoded object matches original
EXPECT_TRUE(compareXnodeObj(&obj, pDecoded));
// Cleanup
taosMemoryFree(obj.url);
taosMemoryFree(obj.status);
taosMemoryFree(pDecoded->url);
taosMemoryFree(pDecoded->status);
taosMemoryFree(pRow);
sdbFreeRaw(pRaw);
}
TEST_F(MndTestXnodeEncodeDecode, test_encode_decode_with_empty_fields) {
// Test with empty URL and status
SXnodeObj obj = {0};
obj.id = 2;
obj.urlLen = 0;
obj.url = NULL;
obj.statusLen = 0;
obj.status = NULL;
obj.createTime = 9876543210;
obj.updateTime = 9876543220;
int32_t rawDataLen = sizeof(SXnodeObj) + 64;
SSdbRaw *pRaw = sdbAllocRaw(SDB_XNODE, 1, rawDataLen);
ASSERT_NE(pRaw, nullptr);
int32_t dataPos = 0;
sdbSetRawInt32(pRaw, dataPos, obj.id);
dataPos += sizeof(obj.id);
sdbSetRawInt32(pRaw, dataPos, obj.urlLen);
dataPos += sizeof(obj.urlLen);
sdbSetRawInt32(pRaw, dataPos, obj.statusLen);
dataPos += sizeof(obj.statusLen);
sdbSetRawInt64(pRaw, dataPos, obj.createTime);
dataPos += sizeof(obj.createTime);
sdbSetRawInt64(pRaw, dataPos, obj.updateTime);
dataPos += sizeof(obj.updateTime);
sdbSetRawDataLen(pRaw, dataPos);
// Decode
SSdbRow *pRow = sdbAllocRow(sizeof(SXnodeObj));
ASSERT_NE(pRow, nullptr);
SXnodeObj *pDecoded = (SXnodeObj *)sdbGetRowObj(pRow);
ASSERT_NE(pDecoded, nullptr);
dataPos = 0;
sdbGetRawInt32(pRaw, dataPos, &pDecoded->id);
dataPos += sizeof(pDecoded->id);
sdbGetRawInt32(pRaw, dataPos, &pDecoded->urlLen);
dataPos += sizeof(pDecoded->urlLen);
sdbGetRawInt32(pRaw, dataPos, &pDecoded->statusLen);
dataPos += sizeof(pDecoded->statusLen);
sdbGetRawInt64(pRaw, dataPos, &pDecoded->createTime);
dataPos += sizeof(pDecoded->createTime);
sdbGetRawInt64(pRaw, dataPos, &pDecoded->updateTime);
dataPos += sizeof(pDecoded->updateTime);
// Verify
EXPECT_EQ(obj.id, pDecoded->id);
EXPECT_EQ(obj.urlLen, pDecoded->urlLen);
EXPECT_EQ(obj.statusLen, pDecoded->statusLen);
EXPECT_EQ(obj.createTime, pDecoded->createTime);
EXPECT_EQ(obj.updateTime, pDecoded->updateTime);
// Cleanup
taosMemoryFree(pRow);
sdbFreeRaw(pRaw);
}
TEST_F(MndTestXnodeEncodeDecode, test_encode_decode_with_max_fields) {
// Test with maximum length fields
SXnodeObj obj = {0};
obj.id = 999;
obj.urlLen = 256; // Max URL length
obj.url = (char *)taosMemoryCalloc(obj.urlLen, 1);
memset(obj.url, 'X', obj.urlLen - 1);
obj.url[obj.urlLen - 1] = '\0';
obj.statusLen = 256; // Reasonable max status length
obj.status = (char *)taosMemoryCalloc(obj.statusLen, 1);
memset(obj.status, 'S', obj.statusLen - 1);
obj.status[obj.statusLen - 1] = '\0';
obj.createTime = INT64_MAX - 1000;
obj.updateTime = INT64_MAX - 500;
int32_t rawDataLen = sizeof(SXnodeObj) + 64 + obj.urlLen + obj.statusLen;
SSdbRaw *pRaw = sdbAllocRaw(SDB_XNODE, 1, rawDataLen);
ASSERT_NE(pRaw, nullptr);
int32_t dataPos = 0;
sdbSetRawInt32(pRaw, dataPos, obj.id);
dataPos += sizeof(obj.id);
sdbSetRawInt32(pRaw, dataPos, obj.urlLen);
dataPos += sizeof(obj.urlLen);
sdbSetRawBinary(pRaw, dataPos, obj.url, obj.urlLen);
dataPos += obj.urlLen;
sdbSetRawInt32(pRaw, dataPos, obj.statusLen);
dataPos += sizeof(obj.statusLen);
sdbSetRawBinary(pRaw, dataPos, obj.status, obj.statusLen);
dataPos += obj.statusLen;
sdbSetRawInt64(pRaw, dataPos, obj.createTime);
dataPos += sizeof(obj.createTime);
sdbSetRawInt64(pRaw, dataPos, obj.updateTime);
dataPos += sizeof(obj.updateTime);
sdbSetRawDataLen(pRaw, dataPos);
// Decode
SSdbRow *pRow = sdbAllocRow(sizeof(SXnodeObj));
ASSERT_NE(pRow, nullptr);
SXnodeObj *pDecoded = (SXnodeObj *)sdbGetRowObj(pRow);
ASSERT_NE(pDecoded, nullptr);
dataPos = 0;
sdbGetRawInt32(pRaw, dataPos, &pDecoded->id);
dataPos += sizeof(pDecoded->id);
sdbGetRawInt32(pRaw, dataPos, &pDecoded->urlLen);
dataPos += sizeof(pDecoded->urlLen);
pDecoded->url = (char *)taosMemoryCalloc(pDecoded->urlLen, 1);
sdbGetRawBinary(pRaw, dataPos, pDecoded->url, pDecoded->urlLen);
dataPos += pDecoded->urlLen;
sdbGetRawInt32(pRaw, dataPos, &pDecoded->statusLen);
dataPos += sizeof(pDecoded->statusLen);
pDecoded->status = (char *)taosMemoryCalloc(pDecoded->statusLen, 1);
sdbGetRawBinary(pRaw, dataPos, pDecoded->status, pDecoded->statusLen);
dataPos += pDecoded->statusLen;
sdbGetRawInt64(pRaw, dataPos, &pDecoded->createTime);
dataPos += sizeof(pDecoded->createTime);
sdbGetRawInt64(pRaw, dataPos, &pDecoded->updateTime);
dataPos += sizeof(pDecoded->updateTime);
// Verify
EXPECT_TRUE(compareXnodeObj(&obj, pDecoded));
// Cleanup
taosMemoryFree(obj.url);
taosMemoryFree(obj.status);
taosMemoryFree(pDecoded->url);
taosMemoryFree(pDecoded->status);
taosMemoryFree(pRow);
sdbFreeRaw(pRaw);
}
TEST_F(MndTestXnodeEncodeDecode, test_xnode_task_basic_encode_decode) {
// Test basic XNode Task encode/decode
// Note: This is a simplified test structure
// In production, use actual SXnodeTaskObj structure from mndDef.h
struct TestTaskObj {
int32_t tid;
char name[TSDB_TABLE_NAME_LEN];
int32_t xnodeId;
int32_t agentId;
int64_t createTime;
int64_t updateTime;
} task = {0};
task.tid = 100;
strcpy(task.name, "test_task_1");
task.xnodeId = 1;
task.agentId = -1;
task.createTime = 1000000;
task.updateTime = 1000100;
// Encode
int32_t rawDataLen = sizeof(TestTaskObj) + 64;
SSdbRaw *pRaw = sdbAllocRaw(SDB_XNODE_TASK, 1, rawDataLen);
ASSERT_NE(pRaw, nullptr);
int32_t dataPos = 0;
sdbSetRawInt32(pRaw, dataPos, task.tid);
dataPos += sizeof(task.tid);
sdbSetRawBinary(pRaw, dataPos, task.name, TSDB_TABLE_NAME_LEN);
dataPos += TSDB_TABLE_NAME_LEN;
sdbSetRawInt32(pRaw, dataPos, task.xnodeId);
dataPos += sizeof(task.xnodeId);
sdbSetRawInt32(pRaw, dataPos, task.agentId);
dataPos += sizeof(task.agentId);
sdbSetRawInt64(pRaw, dataPos, task.createTime);
dataPos += sizeof(task.createTime);
sdbSetRawInt64(pRaw, dataPos, task.updateTime);
dataPos += sizeof(task.updateTime);
sdbSetRawDataLen(pRaw, dataPos);
// Decode
TestTaskObj decoded = {0};
dataPos = 0;
sdbGetRawInt32(pRaw, dataPos, &decoded.tid);
dataPos += sizeof(decoded.tid);
sdbGetRawBinary(pRaw, dataPos, decoded.name, TSDB_TABLE_NAME_LEN);
dataPos += TSDB_TABLE_NAME_LEN;
sdbGetRawInt32(pRaw, dataPos, &decoded.xnodeId);
dataPos += sizeof(decoded.xnodeId);
sdbGetRawInt32(pRaw, dataPos, &decoded.agentId);
dataPos += sizeof(decoded.agentId);
sdbGetRawInt64(pRaw, dataPos, &decoded.createTime);
dataPos += sizeof(decoded.createTime);
sdbGetRawInt64(pRaw, dataPos, &decoded.updateTime);
dataPos += sizeof(decoded.updateTime);
// Verify
EXPECT_EQ(task.tid, decoded.tid);
EXPECT_STREQ(task.name, decoded.name);
EXPECT_EQ(task.xnodeId, decoded.xnodeId);
EXPECT_EQ(task.agentId, decoded.agentId);
EXPECT_EQ(task.createTime, decoded.createTime);
EXPECT_EQ(task.updateTime, decoded.updateTime);
// Cleanup
sdbFreeRaw(pRaw);
}
TEST_F(MndTestXnodeEncodeDecode, test_xnode_job_basic_encode_decode) {
// Test basic XNode Job encode/decode
struct TestJobObj {
int32_t jid;
int32_t tid;
int32_t xnodeId;
int64_t createTime;
int64_t updateTime;
} job = {0};
job.jid = 500;
job.tid = 100;
job.xnodeId = 2;
job.createTime = 2000000;
job.updateTime = 2000200;
// Encode
int32_t rawDataLen = sizeof(TestJobObj) + 64;
SSdbRaw *pRaw = sdbAllocRaw(SDB_XNODE_JOB, 1, rawDataLen);
ASSERT_NE(pRaw, nullptr);
int32_t dataPos = 0;
sdbSetRawInt32(pRaw, dataPos, job.jid);
dataPos += sizeof(job.jid);
sdbSetRawInt32(pRaw, dataPos, job.tid);
dataPos += sizeof(job.tid);
sdbSetRawInt32(pRaw, dataPos, job.xnodeId);
dataPos += sizeof(job.xnodeId);
sdbSetRawInt64(pRaw, dataPos, job.createTime);
dataPos += sizeof(job.createTime);
sdbSetRawInt64(pRaw, dataPos, job.updateTime);
dataPos += sizeof(job.updateTime);
sdbSetRawDataLen(pRaw, dataPos);
// Decode
TestJobObj decoded = {0};
dataPos = 0;
sdbGetRawInt32(pRaw, dataPos, &decoded.jid);
dataPos += sizeof(decoded.jid);
sdbGetRawInt32(pRaw, dataPos, &decoded.tid);
dataPos += sizeof(decoded.tid);
sdbGetRawInt32(pRaw, dataPos, &decoded.xnodeId);
dataPos += sizeof(decoded.xnodeId);
sdbGetRawInt64(pRaw, dataPos, &decoded.createTime);
dataPos += sizeof(decoded.createTime);
sdbGetRawInt64(pRaw, dataPos, &decoded.updateTime);
dataPos += sizeof(decoded.updateTime);
// Verify
EXPECT_EQ(job.jid, decoded.jid);
EXPECT_EQ(job.tid, decoded.tid);
EXPECT_EQ(job.xnodeId, decoded.xnodeId);
EXPECT_EQ(job.createTime, decoded.createTime);
EXPECT_EQ(job.updateTime, decoded.updateTime);
// Cleanup
sdbFreeRaw(pRaw);
}