mirror of
https://github.com/taosdata/TDengine
synced 2026-05-24 10:09:01 +00:00
* feat(taosx): support xnode agent management sql Closes [6646814636](https://project.feishu.cn/taosdata_td/feature/detail/6646814636) * fix some memory leak * chore: fix windows can't find openssl header file * chore: fix memory in xnode agent module * chore: fix and job memory leak * docs: add error code and agent management docs * chore: change the order of QUERY_NODE_ALTER_XNODE_AGENT_STMT
1245 lines
37 KiB
C++
1245 lines
37 KiB
C++
/**
|
|
* @file xnodeSdbTest.cpp
|
|
* @brief Unit tests for XNODE SDB (System Database) operations
|
|
* @version 1.0
|
|
* @date 2025-12-25
|
|
*
|
|
* Tests encode/decode, insert/update/delete operations for:
|
|
* - SXnodeObj
|
|
* - SXnodeTaskObj
|
|
* - SXnodeJobObj
|
|
* - SXnodeUserPassObj
|
|
*
|
|
* NOTE: This test uses simplified mock implementations of encode/decode functions
|
|
* that mirror the logic in production code (mndXnode.c lines 267-359 for XnodeObj,
|
|
* lines 630-768 for XnodeTaskObj). The mock functions use the same data structure
|
|
* layout and serialization order as production, ensuring compatibility.
|
|
*
|
|
* Using mocks instead of production code allows:
|
|
* 1. Faster compilation without complex library dependencies (GEOS, etc.)
|
|
* 2. Isolated testing of serialization logic
|
|
* 3. No need for static function exposure or wrapper files
|
|
*
|
|
* The production encode/decode functions in mndXnode.c are static and include
|
|
* dependencies on many other subsystems. These tests validate the same logical
|
|
* behavior using a simplified, standalone implementation.
|
|
*/
|
|
|
|
#include <gtest/gtest.h>
|
|
#include <cstdint>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
|
|
extern "C" {
|
|
#include "mndXnode.h"
|
|
}
|
|
|
|
// Define reserve size for compatibility with production encode/decode
|
|
#define TSDB_XNODE_RESERVE_SIZE 64
|
|
|
|
// Helper functions
|
|
extern "C" {
|
|
|
|
SSdbRaw* mockAllocRaw(int32_t sdbType, int8_t sver, int32_t dataLen) {
|
|
// SSdbRaw uses flexible array member, allocate in one block
|
|
SSdbRaw* pRaw = (SSdbRaw*)taosMemMalloc(sizeof(SSdbRaw) + dataLen);
|
|
if (!pRaw) return nullptr;
|
|
|
|
pRaw->type = sdbType;
|
|
pRaw->sver = sver;
|
|
pRaw->dataLen = dataLen;
|
|
memset(pRaw->pData, 0, dataLen);
|
|
return pRaw;
|
|
}
|
|
|
|
void mockFreeRaw(SSdbRaw* pRaw) {
|
|
if (!pRaw) return;
|
|
taosMemFree(pRaw);
|
|
}
|
|
|
|
// Simplified encode function for XnodeObj
|
|
SSdbRaw* encodeXnodeObj(SXnodeObj* pObj) {
|
|
int32_t rawDataLen =
|
|
sizeof(int32_t) * 3 + sizeof(int64_t) * 2 + pObj->urlLen + pObj->statusLen + TSDB_XNODE_RESERVE_SIZE;
|
|
|
|
SSdbRaw* pRaw = mockAllocRaw(SDB_XNODE, TSDB_XNODE_VER_NUMBER, rawDataLen);
|
|
if (!pRaw) return nullptr;
|
|
|
|
int32_t pos = 0;
|
|
|
|
// Write id
|
|
memcpy(pRaw->pData + pos, &pObj->id, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
|
|
// Write url
|
|
memcpy(pRaw->pData + pos, &pObj->urlLen, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
if (pObj->urlLen > 0) {
|
|
memcpy(pRaw->pData + pos, pObj->url, pObj->urlLen);
|
|
pos += pObj->urlLen;
|
|
}
|
|
|
|
// Write status
|
|
memcpy(pRaw->pData + pos, &pObj->statusLen, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
if (pObj->statusLen > 0) {
|
|
memcpy(pRaw->pData + pos, pObj->status, pObj->statusLen);
|
|
pos += pObj->statusLen;
|
|
}
|
|
|
|
// Write timestamps
|
|
memcpy(pRaw->pData + pos, &pObj->createTime, sizeof(int64_t));
|
|
pos += sizeof(int64_t);
|
|
memcpy(pRaw->pData + pos, &pObj->updateTime, sizeof(int64_t));
|
|
pos += sizeof(int64_t);
|
|
|
|
return pRaw;
|
|
}
|
|
|
|
// Simplified decode function for XnodeObj
|
|
SXnodeObj* decodeXnodeObj(SSdbRaw* pRaw) {
|
|
if (!pRaw || pRaw->sver != TSDB_XNODE_VER_NUMBER) return nullptr;
|
|
|
|
SXnodeObj* pObj = (SXnodeObj*)taosMemMalloc(sizeof(SXnodeObj));
|
|
if (!pObj) return nullptr;
|
|
memset(pObj, 0, sizeof(SXnodeObj));
|
|
|
|
int32_t pos = 0;
|
|
|
|
// Read id
|
|
memcpy(&pObj->id, pRaw->pData + pos, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
|
|
// Read url
|
|
memcpy(&pObj->urlLen, pRaw->pData + pos, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
if (pObj->urlLen > 0) {
|
|
pObj->url = (char*)taosMemMalloc(pObj->urlLen);
|
|
if (!pObj->url) {
|
|
taosMemFree(pObj);
|
|
return nullptr;
|
|
}
|
|
memcpy(pObj->url, pRaw->pData + pos, pObj->urlLen);
|
|
pos += pObj->urlLen;
|
|
}
|
|
|
|
// Read status
|
|
memcpy(&pObj->statusLen, pRaw->pData + pos, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
if (pObj->statusLen > 0) {
|
|
pObj->status = (char*)taosMemMalloc(pObj->statusLen);
|
|
if (!pObj->status) {
|
|
if (pObj->url) taosMemFree(pObj->url);
|
|
taosMemFree(pObj);
|
|
return nullptr;
|
|
}
|
|
memcpy(pObj->status, pRaw->pData + pos, pObj->statusLen);
|
|
pos += pObj->statusLen;
|
|
}
|
|
|
|
// Read timestamps
|
|
memcpy(&pObj->createTime, pRaw->pData + pos, sizeof(int64_t));
|
|
pos += sizeof(int64_t);
|
|
memcpy(&pObj->updateTime, pRaw->pData + pos, sizeof(int64_t));
|
|
pos += sizeof(int64_t);
|
|
|
|
return pObj;
|
|
}
|
|
|
|
void freeXnodeObj(SXnodeObj* pObj) {
|
|
if (!pObj) return;
|
|
if (pObj->url) taosMemFree(pObj->url);
|
|
if (pObj->status) taosMemFree(pObj->status);
|
|
taosMemFree(pObj);
|
|
}
|
|
|
|
// Forward declarations for free functions used in decode
|
|
void freeXnodeTaskObj(SXnodeTaskObj* pObj);
|
|
void freeXnodeJobObj(SXnodeJobObj* pObj);
|
|
void freeXnodeUserPassObj(SXnodeUserPassObj* pObj);
|
|
|
|
// Encode function for XnodeTaskObj (mirrors mndXnode.c lines 630-674)
|
|
SSdbRaw* encodeXnodeTaskObj(SXnodeTaskObj* pObj) {
|
|
int32_t rawDataLen = sizeof(int32_t) * 10 + sizeof(int64_t) * 2 + pObj->nameLen + pObj->sourceDsnLen +
|
|
pObj->sinkDsnLen + pObj->parserLen + pObj->reasonLen + pObj->statusLen + TSDB_XNODE_RESERVE_SIZE;
|
|
|
|
SSdbRaw* pRaw = mockAllocRaw(SDB_XNODE_TASK, TSDB_XNODE_VER_NUMBER, rawDataLen);
|
|
if (!pRaw) return nullptr;
|
|
|
|
int32_t pos = 0;
|
|
|
|
// Write fields in the same order as production code (lines 641-659)
|
|
memcpy(pRaw->pData + pos, &pObj->id, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
memcpy(pRaw->pData + pos, &pObj->createTime, sizeof(int64_t));
|
|
pos += sizeof(int64_t);
|
|
memcpy(pRaw->pData + pos, &pObj->updateTime, sizeof(int64_t));
|
|
pos += sizeof(int64_t);
|
|
memcpy(pRaw->pData + pos, &pObj->statusLen, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
if (pObj->statusLen > 0) {
|
|
memcpy(pRaw->pData + pos, pObj->status, pObj->statusLen);
|
|
pos += pObj->statusLen;
|
|
}
|
|
memcpy(pRaw->pData + pos, &pObj->via, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
memcpy(pRaw->pData + pos, &pObj->xnodeId, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
memcpy(pRaw->pData + pos, &pObj->nameLen, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
if (pObj->nameLen > 0) {
|
|
memcpy(pRaw->pData + pos, pObj->name, pObj->nameLen);
|
|
pos += pObj->nameLen;
|
|
}
|
|
memcpy(pRaw->pData + pos, &pObj->sourceType, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
memcpy(pRaw->pData + pos, &pObj->sourceDsnLen, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
if (pObj->sourceDsnLen > 0) {
|
|
memcpy(pRaw->pData + pos, pObj->sourceDsn, pObj->sourceDsnLen);
|
|
pos += pObj->sourceDsnLen;
|
|
}
|
|
memcpy(pRaw->pData + pos, &pObj->sinkType, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
memcpy(pRaw->pData + pos, &pObj->sinkDsnLen, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
if (pObj->sinkDsnLen > 0) {
|
|
memcpy(pRaw->pData + pos, pObj->sinkDsn, pObj->sinkDsnLen);
|
|
pos += pObj->sinkDsnLen;
|
|
}
|
|
memcpy(pRaw->pData + pos, &pObj->parserLen, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
if (pObj->parserLen > 0) {
|
|
memcpy(pRaw->pData + pos, pObj->parser, pObj->parserLen);
|
|
pos += pObj->parserLen;
|
|
}
|
|
memcpy(pRaw->pData + pos, &pObj->reasonLen, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
if (pObj->reasonLen > 0) {
|
|
memcpy(pRaw->pData + pos, pObj->reason, pObj->reasonLen);
|
|
pos += pObj->reasonLen;
|
|
}
|
|
|
|
return pRaw;
|
|
}
|
|
|
|
// Decode function for XnodeTaskObj (mirrors mndXnode.c lines 676-769)
|
|
SXnodeTaskObj* decodeXnodeTaskObj(SSdbRaw* pRaw) {
|
|
if (!pRaw || pRaw->sver != TSDB_XNODE_VER_NUMBER) return nullptr;
|
|
|
|
SXnodeTaskObj* pObj = (SXnodeTaskObj*)taosMemMalloc(sizeof(SXnodeTaskObj));
|
|
if (!pObj) return nullptr;
|
|
memset(pObj, 0, sizeof(SXnodeTaskObj));
|
|
|
|
int32_t pos = 0;
|
|
|
|
// Read fields in same order as encode
|
|
memcpy(&pObj->id, pRaw->pData + pos, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
memcpy(&pObj->createTime, pRaw->pData + pos, sizeof(int64_t));
|
|
pos += sizeof(int64_t);
|
|
memcpy(&pObj->updateTime, pRaw->pData + pos, sizeof(int64_t));
|
|
pos += sizeof(int64_t);
|
|
memcpy(&pObj->statusLen, pRaw->pData + pos, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
if (pObj->statusLen > 0) {
|
|
pObj->status = (char*)taosMemMalloc(pObj->statusLen);
|
|
if (!pObj->status) {
|
|
taosMemFree(pObj);
|
|
return nullptr;
|
|
}
|
|
memcpy(pObj->status, pRaw->pData + pos, pObj->statusLen);
|
|
pos += pObj->statusLen;
|
|
}
|
|
memcpy(&pObj->via, pRaw->pData + pos, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
memcpy(&pObj->xnodeId, pRaw->pData + pos, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
memcpy(&pObj->nameLen, pRaw->pData + pos, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
if (pObj->nameLen > 0) {
|
|
pObj->name = (char*)taosMemMalloc(pObj->nameLen);
|
|
if (!pObj->name) {
|
|
freeXnodeTaskObj(pObj);
|
|
return nullptr;
|
|
}
|
|
memcpy(pObj->name, pRaw->pData + pos, pObj->nameLen);
|
|
pos += pObj->nameLen;
|
|
}
|
|
memcpy(&pObj->sourceType, pRaw->pData + pos, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
memcpy(&pObj->sourceDsnLen, pRaw->pData + pos, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
if (pObj->sourceDsnLen > 0) {
|
|
pObj->sourceDsn = (char*)taosMemMalloc(pObj->sourceDsnLen);
|
|
if (!pObj->sourceDsn) {
|
|
freeXnodeTaskObj(pObj);
|
|
return nullptr;
|
|
}
|
|
memcpy(pObj->sourceDsn, pRaw->pData + pos, pObj->sourceDsnLen);
|
|
pos += pObj->sourceDsnLen;
|
|
}
|
|
memcpy(&pObj->sinkType, pRaw->pData + pos, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
memcpy(&pObj->sinkDsnLen, pRaw->pData + pos, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
if (pObj->sinkDsnLen > 0) {
|
|
pObj->sinkDsn = (char*)taosMemMalloc(pObj->sinkDsnLen);
|
|
if (!pObj->sinkDsn) {
|
|
freeXnodeTaskObj(pObj);
|
|
return nullptr;
|
|
}
|
|
memcpy(pObj->sinkDsn, pRaw->pData + pos, pObj->sinkDsnLen);
|
|
pos += pObj->sinkDsnLen;
|
|
}
|
|
memcpy(&pObj->parserLen, pRaw->pData + pos, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
if (pObj->parserLen > 0) {
|
|
pObj->parser = (char*)taosMemMalloc(pObj->parserLen);
|
|
if (!pObj->parser) {
|
|
freeXnodeTaskObj(pObj);
|
|
return nullptr;
|
|
}
|
|
memcpy(pObj->parser, pRaw->pData + pos, pObj->parserLen);
|
|
pos += pObj->parserLen;
|
|
}
|
|
memcpy(&pObj->reasonLen, pRaw->pData + pos, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
if (pObj->reasonLen > 0) {
|
|
pObj->reason = (char*)taosMemMalloc(pObj->reasonLen);
|
|
if (!pObj->reason) {
|
|
freeXnodeTaskObj(pObj);
|
|
return nullptr;
|
|
}
|
|
memcpy(pObj->reason, pRaw->pData + pos, pObj->reasonLen);
|
|
pos += pObj->reasonLen;
|
|
}
|
|
|
|
return pObj;
|
|
}
|
|
|
|
void freeXnodeTaskObj(SXnodeTaskObj* pObj) {
|
|
if (!pObj) return;
|
|
if (pObj->name) taosMemFree(pObj->name);
|
|
if (pObj->sourceDsn) taosMemFree(pObj->sourceDsn);
|
|
if (pObj->sinkDsn) taosMemFree(pObj->sinkDsn);
|
|
if (pObj->parser) taosMemFree(pObj->parser);
|
|
if (pObj->reason) taosMemFree(pObj->reason);
|
|
if (pObj->status) taosMemFree(pObj->status);
|
|
taosMemFree(pObj);
|
|
}
|
|
|
|
// Encode function for XnodeJobObj (mirrors mndXnode.c lines 2104-2143)
|
|
SSdbRaw* encodeXnodeJobObj(SXnodeJobObj* pObj) {
|
|
int32_t rawDataLen = sizeof(int32_t) * 6 + sizeof(int64_t) * 2 + pObj->configLen + pObj->statusLen + pObj->reasonLen +
|
|
TSDB_XNODE_RESERVE_SIZE;
|
|
|
|
SSdbRaw* pRaw = mockAllocRaw(SDB_XNODE_JOB, TSDB_XNODE_VER_NUMBER, rawDataLen);
|
|
if (!pRaw) return nullptr;
|
|
|
|
int32_t pos = 0;
|
|
|
|
memcpy(pRaw->pData + pos, &pObj->id, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
memcpy(pRaw->pData + pos, &pObj->taskId, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
memcpy(pRaw->pData + pos, &pObj->configLen, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
if (pObj->configLen > 0) {
|
|
memcpy(pRaw->pData + pos, pObj->config, pObj->configLen);
|
|
pos += pObj->configLen;
|
|
}
|
|
memcpy(pRaw->pData + pos, &pObj->via, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
memcpy(pRaw->pData + pos, &pObj->xnodeId, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
memcpy(pRaw->pData + pos, &pObj->statusLen, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
if (pObj->statusLen > 0) {
|
|
memcpy(pRaw->pData + pos, pObj->status, pObj->statusLen);
|
|
pos += pObj->statusLen;
|
|
}
|
|
memcpy(pRaw->pData + pos, &pObj->reasonLen, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
if (pObj->reasonLen > 0) {
|
|
memcpy(pRaw->pData + pos, pObj->reason, pObj->reasonLen);
|
|
pos += pObj->reasonLen;
|
|
}
|
|
memcpy(pRaw->pData + pos, &pObj->createTime, sizeof(int64_t));
|
|
pos += sizeof(int64_t);
|
|
memcpy(pRaw->pData + pos, &pObj->updateTime, sizeof(int64_t));
|
|
pos += sizeof(int64_t);
|
|
|
|
return pRaw;
|
|
}
|
|
|
|
// Decode function for XnodeJobObj (mirrors mndXnode.c lines 2145-2215)
|
|
SXnodeJobObj* decodeXnodeJobObj(SSdbRaw* pRaw) {
|
|
if (!pRaw || pRaw->sver != TSDB_XNODE_VER_NUMBER) return nullptr;
|
|
|
|
SXnodeJobObj* pObj = (SXnodeJobObj*)taosMemMalloc(sizeof(SXnodeJobObj));
|
|
if (!pObj) return nullptr;
|
|
memset(pObj, 0, sizeof(SXnodeJobObj));
|
|
|
|
int32_t pos = 0;
|
|
|
|
memcpy(&pObj->id, pRaw->pData + pos, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
memcpy(&pObj->taskId, pRaw->pData + pos, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
memcpy(&pObj->configLen, pRaw->pData + pos, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
if (pObj->configLen > 0) {
|
|
pObj->config = (char*)taosMemMalloc(pObj->configLen);
|
|
if (!pObj->config) {
|
|
taosMemFree(pObj);
|
|
return nullptr;
|
|
}
|
|
memcpy(pObj->config, pRaw->pData + pos, pObj->configLen);
|
|
pos += pObj->configLen;
|
|
}
|
|
memcpy(&pObj->via, pRaw->pData + pos, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
memcpy(&pObj->xnodeId, pRaw->pData + pos, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
memcpy(&pObj->statusLen, pRaw->pData + pos, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
if (pObj->statusLen > 0) {
|
|
pObj->status = (char*)taosMemMalloc(pObj->statusLen);
|
|
if (!pObj->status) {
|
|
if (pObj->config) taosMemFree(pObj->config);
|
|
taosMemFree(pObj);
|
|
return nullptr;
|
|
}
|
|
memcpy(pObj->status, pRaw->pData + pos, pObj->statusLen);
|
|
pos += pObj->statusLen;
|
|
}
|
|
memcpy(&pObj->reasonLen, pRaw->pData + pos, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
if (pObj->reasonLen > 0) {
|
|
pObj->reason = (char*)taosMemMalloc(pObj->reasonLen);
|
|
if (!pObj->reason) {
|
|
if (pObj->config) taosMemFree(pObj->config);
|
|
if (pObj->status) taosMemFree(pObj->status);
|
|
taosMemFree(pObj);
|
|
return nullptr;
|
|
}
|
|
memcpy(pObj->reason, pRaw->pData + pos, pObj->reasonLen);
|
|
pos += pObj->reasonLen;
|
|
}
|
|
memcpy(&pObj->createTime, pRaw->pData + pos, sizeof(int64_t));
|
|
pos += sizeof(int64_t);
|
|
memcpy(&pObj->updateTime, pRaw->pData + pos, sizeof(int64_t));
|
|
pos += sizeof(int64_t);
|
|
|
|
return pObj;
|
|
}
|
|
|
|
void freeXnodeJobObj(SXnodeJobObj* pObj) {
|
|
if (!pObj) return;
|
|
if (pObj->config) taosMemFree(pObj->config);
|
|
if (pObj->status) taosMemFree(pObj->status);
|
|
if (pObj->reason) taosMemFree(pObj->reason);
|
|
taosMemFree(pObj);
|
|
}
|
|
|
|
// Encode function for XnodeUserPassObj (mirrors mndXnode.c lines 2243-2275)
|
|
SSdbRaw* encodeXnodeUserPassObj(SXnodeUserPassObj* pObj) {
|
|
int32_t rawDataLen =
|
|
sizeof(int32_t) * 3 + sizeof(int64_t) * 2 + pObj->userLen + pObj->passLen + TSDB_XNODE_RESERVE_SIZE;
|
|
|
|
SSdbRaw* pRaw = mockAllocRaw(SDB_XNODE_USER_PASS, TSDB_XNODE_VER_NUMBER, rawDataLen);
|
|
if (!pRaw) return nullptr;
|
|
|
|
int32_t pos = 0;
|
|
|
|
memcpy(pRaw->pData + pos, &pObj->id, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
memcpy(pRaw->pData + pos, &pObj->userLen, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
if (pObj->userLen > 0) {
|
|
memcpy(pRaw->pData + pos, pObj->user, pObj->userLen);
|
|
pos += pObj->userLen;
|
|
}
|
|
memcpy(pRaw->pData + pos, &pObj->passLen, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
if (pObj->passLen > 0) {
|
|
memcpy(pRaw->pData + pos, pObj->pass, pObj->passLen);
|
|
pos += pObj->passLen;
|
|
}
|
|
memcpy(pRaw->pData + pos, &pObj->createTime, sizeof(int64_t));
|
|
pos += sizeof(int64_t);
|
|
memcpy(pRaw->pData + pos, &pObj->updateTime, sizeof(int64_t));
|
|
pos += sizeof(int64_t);
|
|
|
|
return pRaw;
|
|
}
|
|
|
|
// Decode function for XnodeUserPassObj (mirrors mndXnode.c lines 2276-2335)
|
|
SXnodeUserPassObj* decodeXnodeUserPassObj(SSdbRaw* pRaw) {
|
|
if (!pRaw || pRaw->sver != TSDB_XNODE_VER_NUMBER) return nullptr;
|
|
|
|
SXnodeUserPassObj* pObj = (SXnodeUserPassObj*)taosMemMalloc(sizeof(SXnodeUserPassObj));
|
|
if (!pObj) return nullptr;
|
|
memset(pObj, 0, sizeof(SXnodeUserPassObj));
|
|
|
|
int32_t pos = 0;
|
|
|
|
memcpy(&pObj->id, pRaw->pData + pos, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
memcpy(&pObj->userLen, pRaw->pData + pos, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
if (pObj->userLen > 0) {
|
|
pObj->user = (char*)taosMemMalloc(pObj->userLen);
|
|
if (!pObj->user) {
|
|
taosMemFree(pObj);
|
|
return nullptr;
|
|
}
|
|
memcpy(pObj->user, pRaw->pData + pos, pObj->userLen);
|
|
pos += pObj->userLen;
|
|
}
|
|
memcpy(&pObj->passLen, pRaw->pData + pos, sizeof(int32_t));
|
|
pos += sizeof(int32_t);
|
|
if (pObj->passLen > 0) {
|
|
pObj->pass = (char*)taosMemMalloc(pObj->passLen);
|
|
if (!pObj->pass) {
|
|
if (pObj->user) taosMemFree(pObj->user);
|
|
taosMemFree(pObj);
|
|
return nullptr;
|
|
}
|
|
memcpy(pObj->pass, pRaw->pData + pos, pObj->passLen);
|
|
pos += pObj->passLen;
|
|
}
|
|
memcpy(&pObj->createTime, pRaw->pData + pos, sizeof(int64_t));
|
|
pos += sizeof(int64_t);
|
|
memcpy(&pObj->updateTime, pRaw->pData + pos, sizeof(int64_t));
|
|
pos += sizeof(int64_t);
|
|
|
|
return pObj;
|
|
}
|
|
|
|
void freeXnodeUserPassObj(SXnodeUserPassObj* pObj) {
|
|
if (!pObj) return;
|
|
if (pObj->user) taosMemFree(pObj->user);
|
|
if (pObj->pass) taosMemFree(pObj->pass);
|
|
taosMemFree(pObj);
|
|
}
|
|
|
|
} // extern "C"
|
|
|
|
class XnodeSdbTest : public ::testing::Test {
|
|
protected:
|
|
void SetUp() override {}
|
|
void TearDown() override {}
|
|
};
|
|
|
|
// ============= SXnodeObj Tests =============
|
|
|
|
TEST_F(XnodeSdbTest, XnodeObj_BasicEncodeDecode) {
|
|
// Create a test object
|
|
SXnodeObj obj = {0};
|
|
obj.id = 1;
|
|
obj.urlLen = 20;
|
|
obj.url = (char*)taosMemMalloc(obj.urlLen);
|
|
strcpy(obj.url, "http://localhost:80");
|
|
obj.statusLen = 7;
|
|
obj.status = (char*)taosMemMalloc(obj.statusLen);
|
|
strcpy(obj.status, "online");
|
|
obj.createTime = 1234567890;
|
|
obj.updateTime = 1234567900;
|
|
|
|
// Encode
|
|
SSdbRaw* pRaw = encodeXnodeObj(&obj);
|
|
ASSERT_NE(pRaw, nullptr);
|
|
EXPECT_EQ(pRaw->type, SDB_XNODE);
|
|
EXPECT_EQ(pRaw->sver, TSDB_XNODE_VER_NUMBER);
|
|
|
|
// Decode
|
|
SXnodeObj* pDecoded = decodeXnodeObj(pRaw);
|
|
ASSERT_NE(pDecoded, nullptr);
|
|
EXPECT_EQ(pDecoded->id, obj.id);
|
|
EXPECT_EQ(pDecoded->urlLen, obj.urlLen);
|
|
EXPECT_STREQ(pDecoded->url, obj.url);
|
|
EXPECT_EQ(pDecoded->statusLen, obj.statusLen);
|
|
EXPECT_STREQ(pDecoded->status, obj.status);
|
|
EXPECT_EQ(pDecoded->createTime, obj.createTime);
|
|
EXPECT_EQ(pDecoded->updateTime, obj.updateTime);
|
|
|
|
// Cleanup
|
|
taosMemFree(obj.url);
|
|
taosMemFree(obj.status);
|
|
mockFreeRaw(pRaw);
|
|
freeXnodeObj(pDecoded);
|
|
}
|
|
|
|
TEST_F(XnodeSdbTest, XnodeObj_EmptyFields) {
|
|
SXnodeObj obj = {0};
|
|
obj.id = 2;
|
|
obj.urlLen = 0;
|
|
obj.url = nullptr;
|
|
obj.statusLen = 0;
|
|
obj.status = nullptr;
|
|
obj.createTime = 1000000;
|
|
obj.updateTime = 2000000;
|
|
|
|
SSdbRaw* pRaw = encodeXnodeObj(&obj);
|
|
ASSERT_NE(pRaw, nullptr);
|
|
|
|
SXnodeObj* pDecoded = decodeXnodeObj(pRaw);
|
|
ASSERT_NE(pDecoded, nullptr);
|
|
EXPECT_EQ(pDecoded->id, obj.id);
|
|
EXPECT_EQ(pDecoded->urlLen, 0);
|
|
EXPECT_EQ(pDecoded->url, nullptr);
|
|
EXPECT_EQ(pDecoded->statusLen, 0);
|
|
EXPECT_EQ(pDecoded->status, nullptr);
|
|
|
|
mockFreeRaw(pRaw);
|
|
freeXnodeObj(pDecoded);
|
|
}
|
|
|
|
TEST_F(XnodeSdbTest, XnodeObj_LongUrl) {
|
|
SXnodeObj obj = {0};
|
|
obj.id = 3;
|
|
obj.urlLen = 200;
|
|
obj.url = (char*)taosMemMalloc(obj.urlLen);
|
|
memset(obj.url, 'x', obj.urlLen - 1);
|
|
obj.url[obj.urlLen - 1] = '\0';
|
|
obj.statusLen = 10;
|
|
obj.status = (char*)taosMemMalloc(obj.statusLen);
|
|
strcpy(obj.status, "running");
|
|
obj.createTime = 111111;
|
|
obj.updateTime = 222222;
|
|
|
|
SSdbRaw* pRaw = encodeXnodeObj(&obj);
|
|
ASSERT_NE(pRaw, nullptr);
|
|
|
|
SXnodeObj* pDecoded = decodeXnodeObj(pRaw);
|
|
ASSERT_NE(pDecoded, nullptr);
|
|
EXPECT_EQ(pDecoded->id, 3);
|
|
EXPECT_EQ(pDecoded->urlLen, 200);
|
|
EXPECT_EQ(memcmp(pDecoded->url, obj.url, obj.urlLen), 0);
|
|
|
|
taosMemFree(obj.url);
|
|
taosMemFree(obj.status);
|
|
mockFreeRaw(pRaw);
|
|
freeXnodeObj(pDecoded);
|
|
}
|
|
|
|
TEST_F(XnodeSdbTest, XnodeObj_InvalidVersion) {
|
|
SXnodeObj obj = {0};
|
|
obj.id = 4;
|
|
obj.createTime = 1000;
|
|
obj.updateTime = 2000;
|
|
|
|
SSdbRaw* pRaw = mockAllocRaw(SDB_XNODE, 99, 1024); // Invalid version
|
|
ASSERT_NE(pRaw, nullptr);
|
|
|
|
SXnodeObj* pDecoded = decodeXnodeObj(pRaw);
|
|
EXPECT_EQ(pDecoded, nullptr); // Should fail due to version mismatch
|
|
|
|
mockFreeRaw(pRaw);
|
|
}
|
|
|
|
TEST_F(XnodeSdbTest, XnodeObj_MultipleEncodeDecode) {
|
|
// Test encoding/decoding multiple objects in sequence
|
|
for (int i = 1; i <= 5; i++) {
|
|
SXnodeObj obj = {0};
|
|
obj.id = i;
|
|
obj.urlLen = 10 + i;
|
|
obj.url = (char*)taosMemMalloc(obj.urlLen);
|
|
snprintf(obj.url, obj.urlLen, "url_%d", i);
|
|
obj.statusLen = 5;
|
|
obj.status = (char*)taosMemMalloc(obj.statusLen);
|
|
strcpy(obj.status, "ok");
|
|
obj.createTime = 1000 * i;
|
|
obj.updateTime = 2000 * i;
|
|
|
|
SSdbRaw* pRaw = encodeXnodeObj(&obj);
|
|
ASSERT_NE(pRaw, nullptr);
|
|
|
|
SXnodeObj* pDecoded = decodeXnodeObj(pRaw);
|
|
ASSERT_NE(pDecoded, nullptr);
|
|
EXPECT_EQ(pDecoded->id, i);
|
|
EXPECT_EQ(pDecoded->createTime, 1000 * i);
|
|
|
|
taosMemFree(obj.url);
|
|
taosMemFree(obj.status);
|
|
mockFreeRaw(pRaw);
|
|
freeXnodeObj(pDecoded);
|
|
}
|
|
}
|
|
|
|
// ============= SXnodeTaskObj Tests =============
|
|
|
|
TEST_F(XnodeSdbTest, XnodeTaskObj_BasicEncodeDecode) {
|
|
SXnodeTaskObj obj = {0};
|
|
obj.id = 100;
|
|
obj.nameLen = 10;
|
|
obj.name = (char*)taosMemMalloc(obj.nameLen);
|
|
strcpy(obj.name, "task_test");
|
|
obj.sourceType = 1;
|
|
obj.sourceDsnLen = 15;
|
|
obj.sourceDsn = (char*)taosMemMalloc(obj.sourceDsnLen);
|
|
strcpy(obj.sourceDsn, "kafka://source");
|
|
obj.sinkType = 2;
|
|
obj.sinkDsnLen = 14;
|
|
obj.sinkDsn = (char*)taosMemMalloc(obj.sinkDsnLen);
|
|
strcpy(obj.sinkDsn, "tdengine://db");
|
|
obj.via = 1;
|
|
obj.xnodeId = 10;
|
|
obj.statusLen = 8;
|
|
obj.status = (char*)taosMemMalloc(obj.statusLen);
|
|
strcpy(obj.status, "running");
|
|
obj.createTime = 5555555;
|
|
obj.updateTime = 6666666;
|
|
|
|
SSdbRaw* pRaw = encodeXnodeTaskObj(&obj);
|
|
ASSERT_NE(pRaw, nullptr);
|
|
EXPECT_EQ(pRaw->type, SDB_XNODE_TASK);
|
|
EXPECT_EQ(pRaw->sver, TSDB_XNODE_VER_NUMBER);
|
|
|
|
// Decode and verify
|
|
SXnodeTaskObj* pDecoded = decodeXnodeTaskObj(pRaw);
|
|
ASSERT_NE(pDecoded, nullptr);
|
|
EXPECT_EQ(pDecoded->id, obj.id);
|
|
EXPECT_EQ(pDecoded->nameLen, obj.nameLen);
|
|
EXPECT_EQ(memcmp(pDecoded->name, obj.name, obj.nameLen), 0);
|
|
EXPECT_EQ(pDecoded->sourceType, obj.sourceType);
|
|
EXPECT_EQ(pDecoded->sourceDsnLen, obj.sourceDsnLen);
|
|
EXPECT_EQ(memcmp(pDecoded->sourceDsn, obj.sourceDsn, obj.sourceDsnLen), 0);
|
|
EXPECT_EQ(pDecoded->sinkType, obj.sinkType);
|
|
EXPECT_EQ(pDecoded->sinkDsnLen, obj.sinkDsnLen);
|
|
EXPECT_EQ(memcmp(pDecoded->sinkDsn, obj.sinkDsn, obj.sinkDsnLen), 0);
|
|
EXPECT_EQ(pDecoded->via, obj.via);
|
|
EXPECT_EQ(pDecoded->xnodeId, obj.xnodeId);
|
|
EXPECT_EQ(pDecoded->createTime, obj.createTime);
|
|
EXPECT_EQ(pDecoded->updateTime, obj.updateTime);
|
|
|
|
taosMemFree(obj.name);
|
|
taosMemFree(obj.sourceDsn);
|
|
taosMemFree(obj.sinkDsn);
|
|
taosMemFree(obj.status);
|
|
mockFreeRaw(pRaw);
|
|
freeXnodeTaskObj(pDecoded);
|
|
}
|
|
|
|
TEST_F(XnodeSdbTest, XnodeTaskObj_EmptyStrings) {
|
|
SXnodeTaskObj obj = {0};
|
|
obj.id = 101;
|
|
obj.nameLen = 0;
|
|
obj.name = nullptr;
|
|
obj.sourceType = 0;
|
|
obj.sourceDsnLen = 0;
|
|
obj.sourceDsn = nullptr;
|
|
obj.sinkType = 0;
|
|
obj.sinkDsnLen = 0;
|
|
obj.sinkDsn = nullptr;
|
|
obj.via = 0;
|
|
obj.xnodeId = 0;
|
|
obj.createTime = 111111;
|
|
obj.updateTime = 222222;
|
|
|
|
SSdbRaw* pRaw = encodeXnodeTaskObj(&obj);
|
|
ASSERT_NE(pRaw, nullptr);
|
|
EXPECT_GT(pRaw->dataLen, 0);
|
|
|
|
SXnodeTaskObj* pDecoded = decodeXnodeTaskObj(pRaw);
|
|
ASSERT_NE(pDecoded, nullptr);
|
|
EXPECT_EQ(pDecoded->id, obj.id);
|
|
EXPECT_EQ(pDecoded->nameLen, 0);
|
|
EXPECT_EQ(pDecoded->name, nullptr);
|
|
|
|
mockFreeRaw(pRaw);
|
|
freeXnodeTaskObj(pDecoded);
|
|
}
|
|
|
|
TEST_F(XnodeSdbTest, XnodeTaskObj_WithParser) {
|
|
SXnodeTaskObj obj = {0};
|
|
obj.id = 102;
|
|
obj.nameLen = 7;
|
|
obj.name = (char*)taosMemMalloc(obj.nameLen);
|
|
strcpy(obj.name, "task_p");
|
|
obj.sourceType = 1;
|
|
obj.sourceDsnLen = 10;
|
|
obj.sourceDsn = (char*)taosMemMalloc(obj.sourceDsnLen);
|
|
strcpy(obj.sourceDsn, "source123");
|
|
obj.sinkType = 2;
|
|
obj.sinkDsnLen = 8;
|
|
obj.sinkDsn = (char*)taosMemMalloc(obj.sinkDsnLen);
|
|
strcpy(obj.sinkDsn, "sink456");
|
|
obj.parserLen = 11;
|
|
obj.parser = (char*)taosMemMalloc(obj.parserLen);
|
|
strcpy(obj.parser, "csv_parser");
|
|
obj.via = 1;
|
|
obj.xnodeId = 5;
|
|
obj.createTime = 1111111;
|
|
obj.updateTime = 2222222;
|
|
|
|
SSdbRaw* pRaw = encodeXnodeTaskObj(&obj);
|
|
ASSERT_NE(pRaw, nullptr);
|
|
|
|
SXnodeTaskObj* pDecoded = decodeXnodeTaskObj(pRaw);
|
|
ASSERT_NE(pDecoded, nullptr);
|
|
EXPECT_EQ(pDecoded->parserLen, obj.parserLen);
|
|
EXPECT_EQ(memcmp(pDecoded->parser, obj.parser, obj.parserLen), 0);
|
|
|
|
taosMemFree(obj.name);
|
|
taosMemFree(obj.sourceDsn);
|
|
taosMemFree(obj.sinkDsn);
|
|
taosMemFree(obj.parser);
|
|
mockFreeRaw(pRaw);
|
|
freeXnodeTaskObj(pDecoded);
|
|
}
|
|
|
|
TEST_F(XnodeSdbTest, XnodeTaskObj_WithReason) {
|
|
SXnodeTaskObj obj = {0};
|
|
obj.id = 103;
|
|
obj.nameLen = 8;
|
|
obj.name = (char*)taosMemMalloc(obj.nameLen);
|
|
strcpy(obj.name, "task123");
|
|
obj.sourceType = 1;
|
|
obj.sourceDsnLen = 5;
|
|
obj.sourceDsn = (char*)taosMemMalloc(obj.sourceDsnLen);
|
|
strcpy(obj.sourceDsn, "src1");
|
|
obj.sinkType = 2;
|
|
obj.sinkDsnLen = 6;
|
|
obj.sinkDsn = (char*)taosMemMalloc(obj.sinkDsnLen);
|
|
strcpy(obj.sinkDsn, "sink1");
|
|
obj.reasonLen = 15;
|
|
obj.reason = (char*)taosMemMalloc(obj.reasonLen);
|
|
strcpy(obj.reason, "timeout_error");
|
|
obj.via = 2;
|
|
obj.xnodeId = 8;
|
|
obj.createTime = 3333333;
|
|
obj.updateTime = 4444444;
|
|
|
|
SSdbRaw* pRaw = encodeXnodeTaskObj(&obj);
|
|
ASSERT_NE(pRaw, nullptr);
|
|
|
|
SXnodeTaskObj* pDecoded = decodeXnodeTaskObj(pRaw);
|
|
ASSERT_NE(pDecoded, nullptr);
|
|
EXPECT_EQ(pDecoded->reasonLen, obj.reasonLen);
|
|
EXPECT_EQ(memcmp(pDecoded->reason, obj.reason, obj.reasonLen), 0);
|
|
EXPECT_EQ(pDecoded->via, 2);
|
|
EXPECT_EQ(pDecoded->xnodeId, 8);
|
|
|
|
taosMemFree(obj.name);
|
|
taosMemFree(obj.sourceDsn);
|
|
taosMemFree(obj.sinkDsn);
|
|
taosMemFree(obj.reason);
|
|
mockFreeRaw(pRaw);
|
|
freeXnodeTaskObj(pDecoded);
|
|
}
|
|
|
|
// ============= SXnodeJobObj Tests =============
|
|
|
|
TEST_F(XnodeSdbTest, XnodeJobObj_BasicEncodeDecode) {
|
|
SXnodeJobObj obj = {0};
|
|
obj.id = 200;
|
|
obj.taskId = 100;
|
|
obj.configLen = 20;
|
|
obj.config = (char*)taosMemMalloc(obj.configLen);
|
|
strcpy(obj.config, "{\"threads\": 4}");
|
|
obj.via = 1;
|
|
obj.xnodeId = 10;
|
|
obj.statusLen = 8;
|
|
obj.status = (char*)taosMemMalloc(obj.statusLen);
|
|
strcpy(obj.status, "running");
|
|
obj.createTime = 7777777;
|
|
obj.updateTime = 8888888;
|
|
|
|
SSdbRaw* pRaw = encodeXnodeJobObj(&obj);
|
|
ASSERT_NE(pRaw, nullptr);
|
|
EXPECT_EQ(pRaw->type, SDB_XNODE_JOB);
|
|
EXPECT_EQ(pRaw->sver, TSDB_XNODE_VER_NUMBER);
|
|
|
|
SXnodeJobObj* pDecoded = decodeXnodeJobObj(pRaw);
|
|
ASSERT_NE(pDecoded, nullptr);
|
|
EXPECT_EQ(pDecoded->id, obj.id);
|
|
EXPECT_EQ(pDecoded->taskId, obj.taskId);
|
|
EXPECT_EQ(pDecoded->configLen, obj.configLen);
|
|
EXPECT_EQ(memcmp(pDecoded->config, obj.config, obj.configLen), 0);
|
|
EXPECT_EQ(pDecoded->via, obj.via);
|
|
EXPECT_EQ(pDecoded->xnodeId, obj.xnodeId);
|
|
EXPECT_EQ(pDecoded->statusLen, obj.statusLen);
|
|
EXPECT_EQ(memcmp(pDecoded->status, obj.status, obj.statusLen), 0);
|
|
EXPECT_EQ(pDecoded->createTime, obj.createTime);
|
|
EXPECT_EQ(pDecoded->updateTime, obj.updateTime);
|
|
|
|
taosMemFree(obj.config);
|
|
taosMemFree(obj.status);
|
|
mockFreeRaw(pRaw);
|
|
freeXnodeJobObj(pDecoded);
|
|
}
|
|
|
|
TEST_F(XnodeSdbTest, XnodeJobObj_EmptyFields) {
|
|
SXnodeJobObj obj = {0};
|
|
obj.id = 201;
|
|
obj.taskId = 101;
|
|
obj.configLen = 0;
|
|
obj.config = nullptr;
|
|
obj.via = 0;
|
|
obj.xnodeId = 0;
|
|
obj.statusLen = 0;
|
|
obj.status = nullptr;
|
|
obj.reasonLen = 0;
|
|
obj.reason = nullptr;
|
|
obj.createTime = 1000000;
|
|
obj.updateTime = 2000000;
|
|
|
|
SSdbRaw* pRaw = encodeXnodeJobObj(&obj);
|
|
ASSERT_NE(pRaw, nullptr);
|
|
|
|
SXnodeJobObj* pDecoded = decodeXnodeJobObj(pRaw);
|
|
ASSERT_NE(pDecoded, nullptr);
|
|
EXPECT_EQ(pDecoded->id, obj.id);
|
|
EXPECT_EQ(pDecoded->taskId, obj.taskId);
|
|
EXPECT_EQ(pDecoded->configLen, 0);
|
|
EXPECT_EQ(pDecoded->config, nullptr);
|
|
|
|
mockFreeRaw(pRaw);
|
|
freeXnodeJobObj(pDecoded);
|
|
}
|
|
|
|
TEST_F(XnodeSdbTest, XnodeJobObj_WithReason) {
|
|
SXnodeJobObj obj = {0};
|
|
obj.id = 202;
|
|
obj.taskId = 102;
|
|
obj.configLen = 15;
|
|
obj.config = (char*)taosMemMalloc(obj.configLen);
|
|
strcpy(obj.config, "{\"batch\": 10}");
|
|
obj.via = 2;
|
|
obj.xnodeId = 20;
|
|
obj.statusLen = 7;
|
|
obj.status = (char*)taosMemMalloc(obj.statusLen);
|
|
strcpy(obj.status, "failed");
|
|
obj.reasonLen = 18;
|
|
obj.reason = (char*)taosMemMalloc(obj.reasonLen);
|
|
strcpy(obj.reason, "connection_failed");
|
|
obj.createTime = 3333333;
|
|
obj.updateTime = 4444444;
|
|
|
|
SSdbRaw* pRaw = encodeXnodeJobObj(&obj);
|
|
ASSERT_NE(pRaw, nullptr);
|
|
|
|
SXnodeJobObj* pDecoded = decodeXnodeJobObj(pRaw);
|
|
ASSERT_NE(pDecoded, nullptr);
|
|
EXPECT_EQ(pDecoded->reasonLen, obj.reasonLen);
|
|
EXPECT_EQ(memcmp(pDecoded->reason, obj.reason, obj.reasonLen), 0);
|
|
|
|
taosMemFree(obj.config);
|
|
taosMemFree(obj.status);
|
|
taosMemFree(obj.reason);
|
|
mockFreeRaw(pRaw);
|
|
freeXnodeJobObj(pDecoded);
|
|
}
|
|
|
|
TEST_F(XnodeSdbTest, XnodeJobObj_LargeConfig) {
|
|
SXnodeJobObj obj = {0};
|
|
obj.id = 203;
|
|
obj.taskId = 103;
|
|
obj.configLen = 100;
|
|
obj.config = (char*)taosMemMalloc(obj.configLen);
|
|
memset(obj.config, 'c', obj.configLen - 1);
|
|
obj.config[obj.configLen - 1] = '\0';
|
|
obj.via = 1;
|
|
obj.xnodeId = 15;
|
|
obj.createTime = 5555555;
|
|
obj.updateTime = 6666666;
|
|
|
|
SSdbRaw* pRaw = encodeXnodeJobObj(&obj);
|
|
ASSERT_NE(pRaw, nullptr);
|
|
|
|
SXnodeJobObj* pDecoded = decodeXnodeJobObj(pRaw);
|
|
ASSERT_NE(pDecoded, nullptr);
|
|
EXPECT_EQ(pDecoded->configLen, obj.configLen);
|
|
EXPECT_EQ(memcmp(pDecoded->config, obj.config, obj.configLen), 0);
|
|
|
|
taosMemFree(obj.config);
|
|
mockFreeRaw(pRaw);
|
|
freeXnodeJobObj(pDecoded);
|
|
}
|
|
|
|
// ============= SXnodeUserPassObj Tests =============
|
|
|
|
TEST_F(XnodeSdbTest, XnodeUserPassObj_BasicEncodeDecode) {
|
|
SXnodeUserPassObj obj = {0};
|
|
obj.id = 300;
|
|
obj.userLen = 10;
|
|
obj.user = (char*)taosMemMalloc(obj.userLen);
|
|
strcpy(obj.user, "testuser1");
|
|
obj.passLen = 15;
|
|
obj.pass = (char*)taosMemMalloc(obj.passLen);
|
|
strcpy(obj.pass, "securepass123");
|
|
obj.createTime = 9999999;
|
|
obj.updateTime = 1111111;
|
|
|
|
SSdbRaw* pRaw = encodeXnodeUserPassObj(&obj);
|
|
ASSERT_NE(pRaw, nullptr);
|
|
EXPECT_EQ(pRaw->type, SDB_XNODE_USER_PASS);
|
|
EXPECT_EQ(pRaw->sver, TSDB_XNODE_VER_NUMBER);
|
|
|
|
SXnodeUserPassObj* pDecoded = decodeXnodeUserPassObj(pRaw);
|
|
ASSERT_NE(pDecoded, nullptr);
|
|
EXPECT_EQ(pDecoded->id, obj.id);
|
|
EXPECT_EQ(pDecoded->userLen, obj.userLen);
|
|
EXPECT_EQ(memcmp(pDecoded->user, obj.user, obj.userLen), 0);
|
|
EXPECT_EQ(pDecoded->passLen, obj.passLen);
|
|
EXPECT_EQ(memcmp(pDecoded->pass, obj.pass, obj.passLen), 0);
|
|
EXPECT_EQ(pDecoded->createTime, obj.createTime);
|
|
EXPECT_EQ(pDecoded->updateTime, obj.updateTime);
|
|
|
|
taosMemFree(obj.user);
|
|
taosMemFree(obj.pass);
|
|
mockFreeRaw(pRaw);
|
|
freeXnodeUserPassObj(pDecoded);
|
|
}
|
|
|
|
TEST_F(XnodeSdbTest, XnodeUserPassObj_EmptyCredentials) {
|
|
SXnodeUserPassObj obj = {0};
|
|
obj.id = 301;
|
|
obj.userLen = 0;
|
|
obj.user = nullptr;
|
|
obj.passLen = 0;
|
|
obj.pass = nullptr;
|
|
obj.createTime = 1234567;
|
|
obj.updateTime = 7654321;
|
|
|
|
SSdbRaw* pRaw = encodeXnodeUserPassObj(&obj);
|
|
ASSERT_NE(pRaw, nullptr);
|
|
|
|
SXnodeUserPassObj* pDecoded = decodeXnodeUserPassObj(pRaw);
|
|
ASSERT_NE(pDecoded, nullptr);
|
|
EXPECT_EQ(pDecoded->id, obj.id);
|
|
EXPECT_EQ(pDecoded->userLen, 0);
|
|
EXPECT_EQ(pDecoded->user, nullptr);
|
|
EXPECT_EQ(pDecoded->passLen, 0);
|
|
EXPECT_EQ(pDecoded->pass, nullptr);
|
|
|
|
mockFreeRaw(pRaw);
|
|
freeXnodeUserPassObj(pDecoded);
|
|
}
|
|
|
|
TEST_F(XnodeSdbTest, XnodeUserPassObj_LongCredentials) {
|
|
SXnodeUserPassObj obj = {0};
|
|
obj.id = 302;
|
|
obj.userLen = 50;
|
|
obj.user = (char*)taosMemMalloc(obj.userLen);
|
|
memset(obj.user, 'u', obj.userLen - 1);
|
|
obj.user[obj.userLen - 1] = '\0';
|
|
obj.passLen = 100;
|
|
obj.pass = (char*)taosMemMalloc(obj.passLen);
|
|
memset(obj.pass, 'p', obj.passLen - 1);
|
|
obj.pass[obj.passLen - 1] = '\0';
|
|
obj.createTime = 5555555;
|
|
obj.updateTime = 6666666;
|
|
|
|
SSdbRaw* pRaw = encodeXnodeUserPassObj(&obj);
|
|
ASSERT_NE(pRaw, nullptr);
|
|
|
|
SXnodeUserPassObj* pDecoded = decodeXnodeUserPassObj(pRaw);
|
|
ASSERT_NE(pDecoded, nullptr);
|
|
EXPECT_EQ(pDecoded->userLen, obj.userLen);
|
|
EXPECT_EQ(memcmp(pDecoded->user, obj.user, obj.userLen), 0);
|
|
EXPECT_EQ(pDecoded->passLen, obj.passLen);
|
|
EXPECT_EQ(memcmp(pDecoded->pass, obj.pass, obj.passLen), 0);
|
|
|
|
taosMemFree(obj.user);
|
|
taosMemFree(obj.pass);
|
|
mockFreeRaw(pRaw);
|
|
freeXnodeUserPassObj(pDecoded);
|
|
}
|
|
|
|
TEST_F(XnodeSdbTest, XnodeUserPassObj_SpecialCharacters) {
|
|
SXnodeUserPassObj obj = {0};
|
|
obj.id = 303;
|
|
obj.userLen = 15;
|
|
obj.user = (char*)taosMemMalloc(obj.userLen);
|
|
strcpy(obj.user, "user@domain");
|
|
obj.passLen = 20;
|
|
obj.pass = (char*)taosMemMalloc(obj.passLen);
|
|
strcpy(obj.pass, "p@ss!w0rd#123");
|
|
obj.createTime = 1111111;
|
|
obj.updateTime = 2222222;
|
|
|
|
SSdbRaw* pRaw = encodeXnodeUserPassObj(&obj);
|
|
ASSERT_NE(pRaw, nullptr);
|
|
|
|
SXnodeUserPassObj* pDecoded = decodeXnodeUserPassObj(pRaw);
|
|
ASSERT_NE(pDecoded, nullptr);
|
|
EXPECT_STREQ(pDecoded->user, obj.user);
|
|
EXPECT_STREQ(pDecoded->pass, obj.pass);
|
|
|
|
taosMemFree(obj.user);
|
|
taosMemFree(obj.pass);
|
|
mockFreeRaw(pRaw);
|
|
freeXnodeUserPassObj(pDecoded);
|
|
}
|
|
|
|
// ============= Cross-object Tests =============
|
|
|
|
TEST_F(XnodeSdbTest, AllObjects_InvalidVersion) {
|
|
// Test that all decode functions reject invalid versions
|
|
SSdbRaw* pRawXnode = mockAllocRaw(SDB_XNODE, 99, 1024);
|
|
SSdbRaw* pRawTask = mockAllocRaw(SDB_XNODE_TASK, 99, 1024);
|
|
SSdbRaw* pRawJob = mockAllocRaw(SDB_XNODE_JOB, 99, 1024);
|
|
SSdbRaw* pRawUser = mockAllocRaw(SDB_XNODE_USER_PASS, 99, 1024);
|
|
|
|
EXPECT_EQ(decodeXnodeObj(pRawXnode), nullptr);
|
|
EXPECT_EQ(decodeXnodeTaskObj(pRawTask), nullptr);
|
|
EXPECT_EQ(decodeXnodeJobObj(pRawJob), nullptr);
|
|
EXPECT_EQ(decodeXnodeUserPassObj(pRawUser), nullptr);
|
|
|
|
mockFreeRaw(pRawXnode);
|
|
mockFreeRaw(pRawTask);
|
|
mockFreeRaw(pRawJob);
|
|
mockFreeRaw(pRawUser);
|
|
}
|
|
|
|
TEST_F(XnodeSdbTest, AllObjects_NullInput) {
|
|
// Test that all decode/free functions handle null gracefully
|
|
EXPECT_EQ(decodeXnodeObj(nullptr), nullptr);
|
|
EXPECT_EQ(decodeXnodeTaskObj(nullptr), nullptr);
|
|
EXPECT_EQ(decodeXnodeJobObj(nullptr), nullptr);
|
|
EXPECT_EQ(decodeXnodeUserPassObj(nullptr), nullptr);
|
|
|
|
// Should not crash
|
|
freeXnodeObj(nullptr);
|
|
freeXnodeTaskObj(nullptr);
|
|
freeXnodeJobObj(nullptr);
|
|
freeXnodeUserPassObj(nullptr);
|
|
SUCCEED();
|
|
}
|
|
|
|
// ============= Memory and Edge Cases =============
|
|
|
|
TEST_F(XnodeSdbTest, XnodeObj_NullRawDecode) {
|
|
SXnodeObj* pDecoded = decodeXnodeObj(nullptr);
|
|
EXPECT_EQ(pDecoded, nullptr);
|
|
}
|
|
|
|
TEST_F(XnodeSdbTest, XnodeObj_FreeNull) {
|
|
// Should not crash
|
|
freeXnodeObj(nullptr);
|
|
SUCCEED();
|
|
}
|
|
|
|
TEST_F(XnodeSdbTest, XnodeTaskObj_FreeNull) {
|
|
// Should not crash
|
|
freeXnodeTaskObj(nullptr);
|
|
SUCCEED();
|
|
}
|
|
|
|
TEST_F(XnodeSdbTest, RawAllocation_OutOfMemory) {
|
|
// Test with very large allocation (simulating OOM)
|
|
SSdbRaw* pRaw = mockAllocRaw(SDB_XNODE, TSDB_XNODE_VER_NUMBER, 0);
|
|
// Should handle gracefully
|
|
if (pRaw) {
|
|
mockFreeRaw(pRaw);
|
|
}
|
|
SUCCEED();
|
|
}
|
|
|
|
TEST_F(XnodeSdbTest, XnodeObj_UpdateScenario) {
|
|
// Simulate an update: old object with one status, new object with another
|
|
SXnodeObj oldObj = {0};
|
|
oldObj.id = 50;
|
|
oldObj.urlLen = 10;
|
|
oldObj.url = (char*)taosMemMalloc(oldObj.urlLen);
|
|
strcpy(oldObj.url, "url_old");
|
|
oldObj.statusLen = 7;
|
|
oldObj.status = (char*)taosMemMalloc(oldObj.statusLen);
|
|
strcpy(oldObj.status, "online");
|
|
oldObj.createTime = 100;
|
|
oldObj.updateTime = 200;
|
|
|
|
SXnodeObj newObj = {0};
|
|
newObj.id = 50;
|
|
newObj.urlLen = 10;
|
|
newObj.url = (char*)taosMemMalloc(newObj.urlLen);
|
|
strcpy(newObj.url, "url_old");
|
|
newObj.statusLen = 8;
|
|
newObj.status = (char*)taosMemMalloc(newObj.statusLen);
|
|
strcpy(newObj.status, "offline");
|
|
newObj.createTime = 100;
|
|
newObj.updateTime = 300;
|
|
|
|
// Encode both
|
|
SSdbRaw* pRawOld = encodeXnodeObj(&oldObj);
|
|
SSdbRaw* pRawNew = encodeXnodeObj(&newObj);
|
|
|
|
ASSERT_NE(pRawOld, nullptr);
|
|
ASSERT_NE(pRawNew, nullptr);
|
|
|
|
// Decode and verify
|
|
SXnodeObj* pDecodedOld = decodeXnodeObj(pRawOld);
|
|
SXnodeObj* pDecodedNew = decodeXnodeObj(pRawNew);
|
|
|
|
ASSERT_NE(pDecodedOld, nullptr);
|
|
ASSERT_NE(pDecodedNew, nullptr);
|
|
|
|
EXPECT_STREQ(pDecodedOld->status, "online");
|
|
EXPECT_STREQ(pDecodedNew->status, "offline");
|
|
EXPECT_EQ(pDecodedNew->updateTime, 300);
|
|
|
|
taosMemFree(oldObj.url);
|
|
taosMemFree(oldObj.status);
|
|
taosMemFree(newObj.url);
|
|
taosMemFree(newObj.status);
|
|
mockFreeRaw(pRawOld);
|
|
mockFreeRaw(pRawNew);
|
|
freeXnodeObj(pDecodedOld);
|
|
freeXnodeObj(pDecodedNew);
|
|
}
|
|
|
|
TEST_F(XnodeSdbTest, XnodeObj_SpecialCharacters) {
|
|
SXnodeObj obj = {0};
|
|
obj.id = 999;
|
|
obj.urlLen = 30;
|
|
obj.url = (char*)taosMemMalloc(obj.urlLen);
|
|
strcpy(obj.url, "http://test.com/path?q=123");
|
|
obj.statusLen = 20;
|
|
obj.status = (char*)taosMemMalloc(obj.statusLen);
|
|
strcpy(obj.status, "status with spaces!");
|
|
obj.createTime = 777777;
|
|
obj.updateTime = 888888;
|
|
|
|
SSdbRaw* pRaw = encodeXnodeObj(&obj);
|
|
ASSERT_NE(pRaw, nullptr);
|
|
|
|
SXnodeObj* pDecoded = decodeXnodeObj(pRaw);
|
|
ASSERT_NE(pDecoded, nullptr);
|
|
EXPECT_STREQ(pDecoded->url, obj.url);
|
|
EXPECT_STREQ(pDecoded->status, obj.status);
|
|
|
|
taosMemFree(obj.url);
|
|
taosMemFree(obj.status);
|
|
mockFreeRaw(pRaw);
|
|
freeXnodeObj(pDecoded);
|
|
}
|
|
|
|
TEST_F(XnodeSdbTest, XnodeObj_ZeroTimestamps) {
|
|
SXnodeObj obj = {0};
|
|
obj.id = 0;
|
|
obj.urlLen = 5;
|
|
obj.url = (char*)taosMemMalloc(obj.urlLen);
|
|
strcpy(obj.url, "test");
|
|
obj.statusLen = 3;
|
|
obj.status = (char*)taosMemMalloc(obj.statusLen);
|
|
strcpy(obj.status, "ok");
|
|
obj.createTime = 0;
|
|
obj.updateTime = 0;
|
|
|
|
SSdbRaw* pRaw = encodeXnodeObj(&obj);
|
|
ASSERT_NE(pRaw, nullptr);
|
|
|
|
SXnodeObj* pDecoded = decodeXnodeObj(pRaw);
|
|
ASSERT_NE(pDecoded, nullptr);
|
|
EXPECT_EQ(pDecoded->createTime, 0);
|
|
EXPECT_EQ(pDecoded->updateTime, 0);
|
|
|
|
taosMemFree(obj.url);
|
|
taosMemFree(obj.status);
|
|
mockFreeRaw(pRaw);
|
|
freeXnodeObj(pDecoded);
|
|
}
|