mirror of
https://github.com/taosdata/TDengine
synced 2026-05-24 10:09:01 +00:00
* 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>
414 lines
13 KiB
C++
414 lines
13 KiB
C++
/**
|
|
* @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);
|
|
}
|