RTU_ALL_AI/src/test/test_datacenter.cpp

895 lines
16 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @file test_datacenter.cpp
* @brief 数据中心模块单元测试
* @details 覆盖生命周期、5 种信号注册/链接、out 延迟回调、yk 同步控制、
* ao SBO 流程、param 多区定值、信号查询、类型工具、事件队列
*/
#include "myDatacenter.h"
#include "myBase.h"
#include <cstdio>
#include <cstring>
#include <cassert>
/* ===== 测试辅助 ===== */
static int g_pass = 0;
static int g_fail = 0;
#define TEST(name) \
do \
{ \
printf(" TEST: %s ... ", name); \
} while (0)
#define OK() \
do \
{ \
printf("OK\n"); \
g_pass++; \
} while (0)
#define FAIL(msg) \
do \
{ \
printf("FAIL: %s\n", msg); \
g_fail++; \
} while (0)
/* ===== 回调测试变量 ===== */
static int g_out_changed = 0;
static int g_yk_changed = 0;
static int g_ao_changed = 0;
static int g_param_changed = 0;
static int g_soe_received = 0;
static void on_out_changed(const char *saddr, uint8_t data_type,
const void *p_new, const void *p_old)
{
(void)saddr;
(void)data_type;
(void)p_new;
(void)p_old;
g_out_changed++;
}
static void on_yk_changed(const char *saddr, dc_ctrl_step_t step,
uint8_t data_type, uint8_t zone,
const void *p_data)
{
(void)saddr;
(void)step;
(void)data_type;
(void)zone;
(void)p_data;
g_yk_changed++;
}
static void on_ao_changed(const char *saddr, dc_ctrl_step_t step,
uint8_t data_type, uint8_t zone,
const void *p_data)
{
(void)saddr;
(void)step;
(void)data_type;
(void)zone;
(void)p_data;
g_ao_changed++;
}
static void on_param_changed(const char *saddr, dc_ctrl_step_t step,
uint8_t data_type, uint8_t zone,
const void *p_data)
{
(void)saddr;
(void)step;
(void)data_type;
(void)zone;
(void)p_data;
g_param_changed++;
}
static void on_soe_pop(void *p_data)
{
(void)p_data;
g_soe_received++;
}
/* ===== 测试用例 ===== */
/**
* @brief 测试 1生命周期
*/
static void test_lifecycle(void)
{
TEST("dc_init()");
{
int r = dc_init(NULL);
if (DC_OK != r)
{
FAIL("init failed");
return;
}
OK();
}
TEST("dc_init() double");
{
int r = dc_init(NULL);
if (DC_OK != r)
{
FAIL("double init should return OK");
return;
}
OK();
}
TEST("dc_cleanup()");
{
dc_cleanup();
/* re-init for following tests */
dc_init(NULL);
OK();
}
}
/**
* @brief 测试 2out 信号注册 + 设值 + 延迟回调
*/
static void test_out_signal(void)
{
int yc_val = 100;
TEST("dc_signal_out()");
{
int r = dc_signal_out("RPC1:YC:1", "test yc", DATA_TYPE_S32,
&yc_val, "protocol");
if (DC_OK != r)
{
FAIL("register failed");
return;
}
OK();
}
TEST("dc_signal_out() duplicate");
{
int r = dc_signal_out("RPC1:YC:1", "dup", DATA_TYPE_S32,
&yc_val, "protocol");
if (DC_ERR_EXISTS != r)
{
FAIL("duplicate should return EXISTS");
return;
}
OK();
}
TEST("dc_signal_out_link_with_callback()");
{
void *p = NULL;
g_out_changed = 0;
int r = dc_signal_out_link_with_callback("RPC1:YC:1", &p,
on_out_changed, "web");
if (DC_OK != r || p != &yc_val)
{
FAIL("link failed");
return;
}
OK();
}
TEST("dc_set_out_signal_val() + dc_run_100ms()");
{
g_out_changed = 0;
yc_val = 200;
int r = dc_set_out_signal_val("RPC1:YC:1", &yc_val, "protocol");
if (DC_OK != r)
{
FAIL("set val failed");
return;
}
/* 回路阻断protocol 自身不会被回调 */
dc_run_100ms();
if (g_out_changed != 1)
{
char msg[64];
snprintf(msg, sizeof(msg), "cb count=%d, expected 1", g_out_changed);
FAIL(msg);
return;
}
OK();
}
}
/**
* @brief 测试 3in 信号注册
*/
static void test_in_signal(void)
{
TEST("dc_signal_in()");
{
void *p = NULL;
int r = dc_signal_in("RPC1:YC:1:in", "test in", "RPC1:YC:1",
&p, "protocol");
if (DC_OK != r || !p)
{
FAIL("in register failed");
return;
}
OK();
}
TEST("dc_signal_in() bad link");
{
void *p = NULL;
int r = dc_signal_in("RPC1:YC:99:in", "bad", "RPC1:YC:99",
&p, "protocol");
if (DC_ERR_NOTFOUND != r)
{
FAIL("bad link should return NOTFOUND");
return;
}
OK();
}
}
/**
* @brief 测试 4yk 信号 + 同步控制
*/
static void test_yk_signal(void)
{
uint8_t yk_val = 0;
TEST("dc_signal_yk()");
{
int r = dc_signal_yk("RPC1:YK:1", "test yk", DATA_TYPE_U8,
DC_CTRL_DIRECT, &yk_val, on_yk_changed, "web");
if (DC_OK != r)
{
FAIL("yk register failed");
return;
}
OK();
}
TEST("dc_signal_yk_set_status() DIRECT");
{
g_yk_changed = 0;
dc_ctrl_t ctrl = {};
ctrl.type = DC_CTRL_DIRECT;
ctrl.data_type = DATA_TYPE_U8;
uint8_t v = 1;
int r = dc_signal_yk_set_status("RPC1:YK:1", DC_STEP_DIRECT,
&ctrl, &v, "protocol");
if (DC_OK != r || yk_val != 1)
{
FAIL("yk set failed");
return;
}
if (g_yk_changed != 1)
{
FAIL("yk callback not triggered");
return;
}
/* 回路阻断web 自身 */ OK();
}
TEST("dc_signal_yk_set_status() SBO flow");
{
g_yk_changed = 0;
dc_ctrl_t ctrl = {};
ctrl.type = DC_CTRL_SBO;
ctrl.data_type = DATA_TYPE_U8;
ctrl.p_data = malloc(1);
*(uint8_t *)ctrl.p_data = 2;
uint8_t sel_val = 2;
int r = dc_signal_yk_set_status("RPC1:YK:1", DC_STEP_SELECT,
&ctrl, &sel_val, "web");
if (DC_OK != r)
{
FAIL("SBO SELECT failed");
free(ctrl.p_data);
return;
}
/* DIRECT with matching value */
r = dc_signal_yk_set_status("RPC1:YK:1", DC_STEP_DIRECT,
&ctrl, &sel_val, "web");
if (DC_OK != r)
{
FAIL("SBO DIRECT failed");
free(ctrl.p_data);
return;
}
free(ctrl.p_data);
OK();
}
}
/**
* @brief 测试 5ao 信号 + SBO 控制
*/
static void test_ao_signal(void)
{
float ao_val = 0.0f;
TEST("dc_signal_ao()");
{
int r = dc_signal_ao("RPC1:AO:1", "test ao", DATA_TYPE_F32,
DC_CTRL_SBO, &ao_val, on_ao_changed, "protocol");
if (DC_OK != r)
{
FAIL("ao register failed");
return;
}
OK();
}
TEST("dc_signal_ao_set_val() SBO");
{
g_ao_changed = 0;
dc_ctrl_t ctrl = {};
ctrl.type = DC_CTRL_SBO;
ctrl.data_type = DATA_TYPE_F32;
ctrl.p_data = malloc(4);
*(float *)ctrl.p_data = 3.14f;
float v = 3.14f;
int r = dc_signal_ao_set_val("RPC1:AO:1", DC_STEP_SELECT,
&ctrl, &v, "web");
if (DC_OK != r)
{
FAIL("ao SELECT failed");
free(ctrl.p_data);
return;
}
r = dc_signal_ao_set_val("RPC1:AO:1", DC_STEP_DIRECT,
&ctrl, &v, "web");
if (DC_OK != r)
{
FAIL("ao DIRECT failed");
free(ctrl.p_data);
return;
}
free(ctrl.p_data);
if (g_ao_changed < 2)
{
FAIL("ao callback not triggered");
return;
}
/* ctrl->step should be reset to READY */
if (ctrl.step != DC_STEP_READY)
{
FAIL("ctrl step not reset to READY");
return;
}
OK();
}
TEST("dc_signal_ao_set_val_without_check()");
{
g_ao_changed = 0;
float v = 2.71f;
int r = dc_signal_ao_set_val_without_check("RPC1:AO:1", DATA_TYPE_F32,
&v, "protocol");
if (DC_OK != r)
{
FAIL("ao set without check failed");
return;
}
OK();
}
}
/**
* @brief 测试 6param 多区定值
*/
static void test_param_signal(void)
{
uint32_t p1 = 10;
uint32_t p2 = 20;
void *parr[2] = {&p1, &p2};
TEST("dc_signal_param()");
{
int r = dc_signal_param("RPC1:PARAM:1", "test param", DATA_TYPE_U32,
DC_CTRL_SBO, parr, 2, on_param_changed, "web");
if (DC_OK != r)
{
FAIL("param register failed");
return;
}
OK();
}
TEST("dc_signal_param_set_val() zone 0");
{
g_param_changed = 0;
dc_ctrl_t ctrl = {};
ctrl.type = DC_CTRL_SBO;
ctrl.data_type = DATA_TYPE_U32;
ctrl.p_data = malloc(4);
*(uint32_t *)ctrl.p_data = 55;
uint32_t v = 55;
int r = dc_signal_param_set_val("RPC1:PARAM:1", DC_STEP_SELECT,
&ctrl, 0, &v, "web");
if (DC_OK != r)
{
FAIL("param SELECT failed");
free(ctrl.p_data);
return;
}
r = dc_signal_param_set_val("RPC1:PARAM:1", DC_STEP_DIRECT,
&ctrl, 0, &v, "web");
if (DC_OK != r)
{
FAIL("param DIRECT failed");
free(ctrl.p_data);
return;
}
free(ctrl.p_data);
if (p1 != 55)
{
FAIL("zone0 not updated");
return;
}
OK();
}
}
/**
* @brief 测试 7信号查询
*/
static void test_query(void)
{
TEST("dc_get_out_signal_info()");
{
char desc[64] = {0};
uint8_t dt = 0;
void *p = NULL;
int r = dc_get_out_signal_info("RPC1:YC:1", desc, 64, &dt, &p);
if (DC_OK != r || dt != DATA_TYPE_S32)
{
FAIL("query out failed");
return;
}
OK();
}
TEST("dc_get_signal_count()");
{
int n = dc_get_signal_count("out");
if (n < 1)
{
FAIL("out count should be >= 1");
return;
}
n = dc_get_signal_count("param");
if (n < 1)
{
FAIL("param count should be >= 1");
return;
}
OK();
}
TEST("dc_get_signal_info_by_id()");
{
char saddr[64] = {0};
char desc[64] = {0};
char dtstr[32] = {0};
uint8_t ct = 0;
int r = dc_get_signal_info_by_id("out", 0, saddr, 64, desc, 64,
dtstr, 32, &ct, NULL, 0);
if (DC_OK != r)
{
FAIL("get by id failed");
return;
}
OK();
}
TEST("dc_get_signal_val()");
{
uint32_t v = 42;
char buf[32] = {0};
int r = dc_get_signal_val(&v, DATA_TYPE_U32, buf, 32);
if (DC_OK != r || 0 != strcmp(buf, "42"))
{
FAIL("val to str failed");
return;
}
OK();
}
}
/**
* @brief 测试 8类型工具
*/
static void test_type_util(void)
{
TEST("dc_get_type_name()");
{
const char *n = dc_get_type_name(DATA_TYPE_F32);
if (0 != strcmp(n, "float"))
{
FAIL("type name mismatch");
return;
}
OK();
}
TEST("dc_get_type_id_by_name()");
{
uint8_t id = dc_get_type_id_by_name("uint32_t");
if (DATA_TYPE_U32 != id)
{
FAIL("type id mismatch");
return;
}
OK();
}
TEST("dc_get_type_len()");
{
if (4 != dc_get_type_len(DATA_TYPE_F32))
{
FAIL("float len should be 4");
return;
}
if (8 != dc_get_type_len(DATA_TYPE_D64))
{
FAIL("double len should be 8");
return;
}
OK();
}
TEST("dc_create_data + dc_destroy_data");
{
void *p = dc_create_data(DATA_TYPE_S32);
if (!p)
{
FAIL("create data failed");
return;
}
dc_destroy_data(p, DATA_TYPE_S32);
OK();
}
TEST("dc_copy_val + dc_compare_val");
{
int a = 10;
int b = 0;
dc_copy_val(&b, &a, DATA_TYPE_S32);
if (b != 10)
{
FAIL("copy val failed");
return;
}
if (0 != dc_compare_val(&a, &b, DATA_TYPE_S32))
{
FAIL("compare equal failed");
return;
}
b = 20;
if (-1 != dc_compare_val(&a, &b, DATA_TYPE_S32))
{
FAIL("compare unequal failed");
return;
}
OK();
}
TEST("dc_set_val_from_str()");
{
float f = 0.0f;
int r = dc_set_val_from_str(&f, DATA_TYPE_F32, "3.14");
if (DC_OK != r || f < 3.13f || f > 3.15f)
{
FAIL("set from str failed");
return;
}
OK();
}
TEST("dc_set_val_from_str() IP");
{
uint8_t ip[4] = {0};
int r = dc_set_val_from_str(ip, DATA_TYPE_IP, "192.168.1.1");
if (DC_OK != r || ip[0] != 192 || ip[1] != 168 || ip[2] != 1 || ip[3] != 1)
{
FAIL("IP parse failed");
return;
}
OK();
}
}
/**
* @brief 测试 9事件队列
*/
static void test_event_queue(void)
{
TEST("dc_event_queue_push + register");
{
int r = dc_event_register_queue_pop(on_soe_pop);
if (DC_OK != r)
{
FAIL("register pop failed");
return;
}
g_soe_received = 0;
int dummy = 99;
r = dc_event_queue_push(&dummy);
if (DC_OK != r)
{
FAIL("event push failed");
return;
}
/* 消耗队列 */
dc_run_100ms();
if (g_soe_received < 1)
{
FAIL("event not consumed");
return;
}
OK();
}
TEST("dc_disturb_dd_queue_push");
{
int dummy = 1;
int r = dc_disturb_dd_queue_push(&dummy);
if (DC_OK != r)
{
FAIL("disturb push failed");
return;
}
OK();
}
TEST("dc_fault_queue_push");
{
int dummy = 1;
int r = dc_fault_queue_push(&dummy);
if (DC_OK != r)
{
FAIL("fault push failed");
return;
}
OK();
}
}
/**
* @brief 测试 10异步管理
*/
static void test_async_mgmt(void)
{
TEST("dc_async_pending_count()");
{
int n = dc_async_pending_count();
if (n < 0)
{
FAIL("pending count failed");
return;
}
OK();
}
TEST("dc_async_set_default_timeout()");
{
dc_async_set_default_timeout(5000);
OK();
}
TEST("dc_param_cfg_changed()");
{
int r = dc_param_cfg_changed();
if (r < 0)
{
FAIL("cfg changed failed");
return;
}
OK();
}
}
/* ===== 入口 ===== */
int main(void)
{
printf("=== test_datacenter ===\n\n");
/* 初始化 */
dc_init(NULL);
/* 信号注册 */
test_out_signal();
test_in_signal();
test_yk_signal();
test_ao_signal();
test_param_signal();
/* 查询 */
test_query();
/* 工具 */
test_type_util();
/* 事件队列 */
test_event_queue();
/* 异步管理 */
test_async_mgmt();
/* 清理 */
dc_cleanup();
/* 生命周期 */
dc_init(NULL);
test_lifecycle();
dc_cleanup();
/* 结果 */
printf("\n=== result: %d pass, %d fail ===\n", g_pass, g_fail);
return (g_fail > 0) ? 1 : 0;
}