mirror of
https://github.com/emqx/neuron.git
synced 2026-10-29 23:19:18 +08:00
Merge pull request #1621 from hxy7yx/main-3
feat(restful): Add API for single-request bulk tag addition across multiple groups
This commit is contained in:
@@ -89,6 +89,8 @@ typedef enum neu_reqresp_type {
|
||||
|
||||
NEU_REQ_ADD_TAG,
|
||||
NEU_RESP_ADD_TAG,
|
||||
NEU_REQ_ADD_GTAG,
|
||||
NEU_RESP_ADD_GTAG,
|
||||
NEU_REQ_DEL_TAG,
|
||||
NEU_REQ_UPDATE_TAG,
|
||||
NEU_RESP_UPDATE_TAG,
|
||||
@@ -197,6 +199,8 @@ static const char *neu_reqresp_type_string_t[] = {
|
||||
|
||||
[NEU_REQ_ADD_TAG] = "NEU_REQ_ADD_TAG",
|
||||
[NEU_RESP_ADD_TAG] = "NEU_RESP_ADD_TAG",
|
||||
[NEU_REQ_ADD_GTAG] = "NEU_REQ_ADD_GTAG",
|
||||
[NEU_RESP_ADD_GTAG] = "NEU_RESP_ADD_GTAG",
|
||||
[NEU_REQ_DEL_TAG] = "NEU_REQ_DEL_TAG",
|
||||
[NEU_REQ_UPDATE_TAG] = "NEU_REQ_UPDATE_TAG",
|
||||
[NEU_RESP_UPDATE_TAG] = "NEU_RESP_UPDATE_TAG",
|
||||
@@ -384,6 +388,19 @@ typedef struct neu_resp_get_group {
|
||||
UT_array *groups; // array neu_resp_group_info_t
|
||||
} neu_resp_get_group_t;
|
||||
|
||||
typedef struct {
|
||||
char group[NEU_GROUP_NAME_LEN];
|
||||
int n_tag;
|
||||
int interval;
|
||||
neu_datatag_t *tags;
|
||||
} neu_gdatatag_t;
|
||||
|
||||
typedef struct {
|
||||
char driver[NEU_NODE_NAME_LEN];
|
||||
uint16_t n_group;
|
||||
neu_gdatatag_t *groups;
|
||||
} neu_req_add_gtag_t;
|
||||
|
||||
typedef struct {
|
||||
char driver[NEU_NODE_NAME_LEN];
|
||||
char group[NEU_GROUP_NAME_LEN];
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#define NEU_TAG_DESCRIPTION_LEN 128
|
||||
#define NEU_GROUP_NAME_LEN 128
|
||||
#define NEU_GROUP_INTERVAL_LIMIT 100
|
||||
#define NEU_DEFAULT_GROUP_INTERVAL 100
|
||||
#define NEU_NODE_NAME_LEN 128
|
||||
#define NEU_PLUGIN_NAME_LEN 32
|
||||
#define NEU_PLUGIN_LIBRARY_LEN 32
|
||||
|
||||
@@ -96,6 +96,98 @@ void handle_add_tags_resp(nng_aio *aio, neu_resp_add_tag_t *resp)
|
||||
free(result);
|
||||
}
|
||||
|
||||
void handle_add_gtags(nng_aio *aio)
|
||||
{
|
||||
neu_plugin_t *plugin = neu_rest_get_plugin();
|
||||
|
||||
NEU_PROCESS_HTTP_REQUEST_VALIDATE_JWT(
|
||||
aio, neu_json_add_gtags_req_t, neu_json_decode_add_gtags_req, {
|
||||
int ret = 0;
|
||||
neu_reqresp_head_t header = { 0 };
|
||||
neu_req_add_gtag_t cmd = { 0 };
|
||||
int err_type;
|
||||
header.ctx = aio;
|
||||
header.type = NEU_REQ_ADD_GTAG;
|
||||
|
||||
for (int i = 0; i < req->n_group; i++) {
|
||||
if (strlen(req->groups[i].group) >= NEU_GROUP_NAME_LEN) {
|
||||
err_type = NEU_ERR_GROUP_NAME_TOO_LONG;
|
||||
goto error;
|
||||
}
|
||||
if (req->groups[i].interval < NEU_DEFAULT_GROUP_INTERVAL) {
|
||||
err_type = NEU_ERR_GROUP_PARAMETER_INVALID;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
strcpy(cmd.driver, req->node);
|
||||
cmd.n_group = req->n_group;
|
||||
|
||||
cmd.groups = calloc(req->n_group, sizeof(neu_gdatatag_t));
|
||||
for (int i = 0; i < req->n_group; i++) {
|
||||
strcpy(cmd.groups[i].group, req->groups[i].group);
|
||||
cmd.groups[i].n_tag = req->groups[i].n_tag;
|
||||
cmd.groups[i].interval = req->groups[i].interval;
|
||||
cmd.groups[i].tags =
|
||||
calloc(cmd.groups[i].n_tag, sizeof(neu_datatag_t));
|
||||
|
||||
for (int j = 0; j < req->groups[i].n_tag; j++) {
|
||||
cmd.groups[i].tags[j].attribute =
|
||||
req->groups[i].tags[j].attribute;
|
||||
cmd.groups[i].tags[j].type = req->groups[i].tags[j].type;
|
||||
cmd.groups[i].tags[j].precision =
|
||||
req->groups[i].tags[j].precision;
|
||||
cmd.groups[i].tags[j].decimal =
|
||||
req->groups[i].tags[j].decimal;
|
||||
cmd.groups[i].tags[j].address =
|
||||
strdup(req->groups[i].tags[j].address);
|
||||
cmd.groups[i].tags[j].name =
|
||||
strdup(req->groups[i].tags[j].name);
|
||||
if (req->groups[i].tags[j].description != NULL) {
|
||||
cmd.groups[i].tags[j].description =
|
||||
strdup(req->groups[i].tags[j].description);
|
||||
} else {
|
||||
cmd.groups[i].tags[j].description = strdup("");
|
||||
}
|
||||
if (NEU_ATTRIBUTE_STATIC &
|
||||
req->groups[i].tags[j].attribute) {
|
||||
neu_tag_set_static_value_json(
|
||||
&cmd.groups[i].tags[j], req->groups[i].tags[j].t,
|
||||
&req->groups[i].tags[j].value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = neu_plugin_op(plugin, header, &cmd);
|
||||
if (ret != 0) {
|
||||
NEU_JSON_RESPONSE_ERROR(NEU_ERR_IS_BUSY, {
|
||||
neu_http_response(aio, NEU_ERR_IS_BUSY, result_error);
|
||||
});
|
||||
}
|
||||
goto success;
|
||||
|
||||
error:
|
||||
NEU_JSON_RESPONSE_ERROR(
|
||||
err_type, { neu_http_response(aio, err_type, result_error); });
|
||||
|
||||
success:;
|
||||
})
|
||||
}
|
||||
|
||||
void handle_add_gtags_resp(nng_aio *aio, neu_resp_add_tag_t *resp)
|
||||
{
|
||||
neu_json_add_gtag_res_t res = { 0 };
|
||||
char * result = NULL;
|
||||
|
||||
res.error = resp->error;
|
||||
res.index = resp->index;
|
||||
|
||||
neu_json_encode_by_fn(&res, neu_json_encode_au_gtags_resp, &result);
|
||||
|
||||
neu_http_ok(aio, result);
|
||||
free(result);
|
||||
}
|
||||
|
||||
void handle_del_tags(nng_aio *aio)
|
||||
{
|
||||
neu_plugin_t *plugin = neu_rest_get_plugin();
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
|
||||
void handle_add_tags(nng_aio *aio);
|
||||
void handle_add_tags_resp(nng_aio *aio, neu_resp_add_tag_t *resp);
|
||||
void handle_add_gtags(nng_aio *aio);
|
||||
void handle_add_gtags_resp(nng_aio *aio, neu_resp_add_tag_t *resp);
|
||||
void handle_del_tags(nng_aio *aio);
|
||||
void handle_update_tags(nng_aio *aio);
|
||||
void handle_update_tags_resp(nng_aio *aio, neu_resp_update_tag_t *resp);
|
||||
|
||||
@@ -56,6 +56,9 @@ static struct neu_http_handler cors_handler[] = {
|
||||
{
|
||||
.url = "/api/v2/tags",
|
||||
},
|
||||
{
|
||||
.url = "/api/v2/gtags",
|
||||
},
|
||||
{
|
||||
.url = "/api/v2/group",
|
||||
},
|
||||
@@ -183,12 +186,17 @@ static struct neu_http_handler rest_handlers[] = {
|
||||
.value.handler = handle_add_tags,
|
||||
|
||||
},
|
||||
{
|
||||
.method = NEU_HTTP_METHOD_POST,
|
||||
.type = NEU_HTTP_HANDLER_FUNCTION,
|
||||
.url = "/api/v2/gtags",
|
||||
.value.handler = handle_add_gtags,
|
||||
},
|
||||
{
|
||||
.method = NEU_HTTP_METHOD_PUT,
|
||||
.type = NEU_HTTP_HANDLER_FUNCTION,
|
||||
.url = "/api/v2/tags",
|
||||
.value.handler = handle_update_tags,
|
||||
|
||||
},
|
||||
{
|
||||
.method = NEU_HTTP_METHOD_GET,
|
||||
|
||||
@@ -198,6 +198,9 @@ static int dashb_plugin_request(neu_plugin_t * plugin,
|
||||
case NEU_RESP_ADD_TEMPLATE_TAG:
|
||||
handle_add_tags_resp(header->ctx, (neu_resp_add_tag_t *) data);
|
||||
break;
|
||||
case NEU_RESP_ADD_GTAG:
|
||||
handle_add_gtags_resp(header->ctx, (neu_resp_add_tag_t *) data);
|
||||
break;
|
||||
case NEU_RESP_UPDATE_TAG:
|
||||
case NEU_RESP_UPDATE_TEMPLATE_TAG:
|
||||
handle_update_tags_resp(header->ctx, (neu_resp_update_tag_t *) data);
|
||||
|
||||
+87
-1
@@ -454,6 +454,11 @@ static int adapter_command(neu_adapter_t *adapter, neu_reqresp_head_t header,
|
||||
strcpy(pheader->receiver, cmd->driver);
|
||||
break;
|
||||
}
|
||||
case NEU_REQ_ADD_GTAG: {
|
||||
neu_req_add_gtag_t *cmd = (neu_req_add_gtag_t *) data;
|
||||
strcpy(pheader->receiver, cmd->driver);
|
||||
break;
|
||||
}
|
||||
case NEU_REQ_UPDATE_NODE:
|
||||
case NEU_REQ_NODE_CTL:
|
||||
case NEU_REQ_GET_NODE_STATE:
|
||||
@@ -639,6 +644,7 @@ static int adapter_loop(enum neu_event_io_type type, int fd, void *usr_data)
|
||||
case NEU_REQ_UPDATE_GROUP:
|
||||
case NEU_RESP_GET_SUBSCRIBE_GROUP:
|
||||
case NEU_RESP_ADD_TAG:
|
||||
case NEU_RESP_ADD_GTAG:
|
||||
case NEU_RESP_ADD_TEMPLATE_TAG:
|
||||
case NEU_RESP_UPDATE_TAG:
|
||||
case NEU_RESP_UPDATE_TEMPLATE_TAG:
|
||||
@@ -998,7 +1004,8 @@ static int adapter_loop(enum neu_event_io_type type, int fd, void *usr_data)
|
||||
|
||||
for (int i = 0; i < resp.index; i++) {
|
||||
int ret = neu_adapter_driver_add_tag(
|
||||
(neu_adapter_driver_t *) adapter, cmd->group, &cmd->tags[i]);
|
||||
(neu_adapter_driver_t *) adapter, cmd->group, &cmd->tags[i],
|
||||
NEU_DEFAULT_GROUP_INTERVAL);
|
||||
if (ret != 0) {
|
||||
neu_adapter_driver_try_del_tag((neu_adapter_driver_t *) adapter,
|
||||
resp.index - i);
|
||||
@@ -1027,6 +1034,81 @@ static int adapter_loop(enum neu_event_io_type type, int fd, void *usr_data)
|
||||
reply(adapter, header, &resp);
|
||||
break;
|
||||
}
|
||||
case NEU_REQ_ADD_GTAG: {
|
||||
neu_req_add_gtag_t *cmd = (neu_req_add_gtag_t *) &header[1];
|
||||
neu_resp_add_tag_t resp = { 0 };
|
||||
if (adapter->module->type == NEU_NA_TYPE_DRIVER) {
|
||||
for (int i = 0; i < cmd->n_group; i++) {
|
||||
for (int j = 0; j < cmd->groups[i].n_tag; j++) {
|
||||
int ret = neu_adapter_driver_validate_tag(
|
||||
(neu_adapter_driver_t *) adapter, cmd->groups[i].group,
|
||||
&cmd->groups[i].tags[j]);
|
||||
if (ret == 0) {
|
||||
resp.index += 1;
|
||||
} else {
|
||||
resp.error = ret;
|
||||
resp.index = 0;
|
||||
i = cmd->n_group;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
resp.error = NEU_ERR_GROUP_NOT_ALLOW;
|
||||
}
|
||||
if (resp.index > 0) {
|
||||
for (int i = 0; i < cmd->n_group; i++) {
|
||||
int ret = neu_adapter_driver_try_add_tag(
|
||||
(neu_adapter_driver_t *) adapter, cmd->groups[i].group,
|
||||
cmd->groups[i].tags, cmd->groups[i].n_tag);
|
||||
if (ret != 0) {
|
||||
resp.index = 0;
|
||||
resp.error = ret;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (resp.index > 0) {
|
||||
for (int i = 0; i < cmd->n_group; i++) {
|
||||
for (int j = 0; j < cmd->groups[i].n_tag; j++) {
|
||||
int ret = neu_adapter_driver_add_tag(
|
||||
(neu_adapter_driver_t *) adapter, cmd->groups[i].group,
|
||||
&cmd->groups[i].tags[j], cmd->groups[i].interval);
|
||||
if (ret != 0) {
|
||||
neu_adapter_driver_try_del_tag(
|
||||
(neu_adapter_driver_t *) adapter,
|
||||
cmd->groups[i].n_tag - j);
|
||||
resp.index = 0;
|
||||
i = cmd->n_group;
|
||||
resp.error = ret;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (resp.index) {
|
||||
for (int i = 0; i < cmd->n_group; i++) {
|
||||
adapter_storage_add_tags(cmd->driver, cmd->groups[i].group,
|
||||
cmd->groups[i].tags,
|
||||
cmd->groups[i].n_tag);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < cmd->n_group; i++) {
|
||||
for (int j = 0; j < cmd->groups[i].n_tag; j++) {
|
||||
neu_tag_fini(&cmd->groups[i].tags[j]);
|
||||
}
|
||||
free(cmd->groups[i].tags);
|
||||
}
|
||||
free(cmd->groups);
|
||||
|
||||
neu_msg_exchange(header);
|
||||
header->type = NEU_RESP_ADD_GTAG;
|
||||
reply(adapter, header, &resp);
|
||||
break;
|
||||
}
|
||||
case NEU_REQ_UPDATE_TAG: {
|
||||
neu_req_update_tag_t *cmd = (neu_req_update_tag_t *) &header[1];
|
||||
neu_resp_update_tag_t resp = { 0 };
|
||||
@@ -1643,9 +1725,13 @@ void neu_msg_gen(neu_reqresp_head_t *header, void *data)
|
||||
data_size = sizeof(neu_req_add_tag_t);
|
||||
break;
|
||||
case NEU_RESP_ADD_TAG:
|
||||
case NEU_RESP_ADD_GTAG:
|
||||
case NEU_RESP_ADD_TEMPLATE_TAG:
|
||||
data_size = sizeof(neu_resp_add_tag_t);
|
||||
break;
|
||||
case NEU_REQ_ADD_GTAG:
|
||||
data_size = sizeof(neu_req_add_gtag_t);
|
||||
break;
|
||||
case NEU_RESP_UPDATE_TAG:
|
||||
case NEU_RESP_UPDATE_TEMPLATE_TAG:
|
||||
data_size = sizeof(neu_resp_update_tag_t);
|
||||
|
||||
@@ -1195,7 +1195,7 @@ int neu_adapter_driver_validate_tag(neu_adapter_driver_t *driver,
|
||||
}
|
||||
|
||||
int neu_adapter_driver_add_tag(neu_adapter_driver_t *driver, const char *group,
|
||||
neu_datatag_t *tag)
|
||||
neu_datatag_t *tag, uint16_t interval)
|
||||
{
|
||||
int ret = NEU_ERR_SUCCESS;
|
||||
group_t *find = NULL;
|
||||
@@ -1206,8 +1206,8 @@ int neu_adapter_driver_add_tag(neu_adapter_driver_t *driver, const char *group,
|
||||
|
||||
HASH_FIND_STR(driver->groups, group, find);
|
||||
if (find == NULL) {
|
||||
neu_adapter_driver_add_group(driver, group, 100);
|
||||
adapter_storage_add_group(driver->adapter.name, group, 100);
|
||||
neu_adapter_driver_add_group(driver, group, interval);
|
||||
adapter_storage_add_group(driver->adapter.name, group, interval);
|
||||
}
|
||||
HASH_FIND_STR(driver->groups, group, find);
|
||||
assert(find != NULL);
|
||||
|
||||
@@ -65,7 +65,7 @@ int neu_adapter_driver_validate_tag(neu_adapter_driver_t *driver,
|
||||
const char *group, neu_datatag_t *tag);
|
||||
|
||||
int neu_adapter_driver_add_tag(neu_adapter_driver_t *driver, const char *group,
|
||||
neu_datatag_t *tag);
|
||||
neu_datatag_t *tag, uint16_t interval);
|
||||
int neu_adapter_driver_del_tag(neu_adapter_driver_t *driver, const char *group,
|
||||
const char *tag);
|
||||
int neu_adapter_driver_update_tag(neu_adapter_driver_t *driver,
|
||||
|
||||
@@ -156,7 +156,7 @@ int adapter_load_group_and_tag(neu_adapter_driver_t *driver)
|
||||
|
||||
utarray_foreach(tags, neu_datatag_t *, tag)
|
||||
{
|
||||
neu_adapter_driver_add_tag(driver, p->name, tag);
|
||||
neu_adapter_driver_add_tag(driver, p->name, tag, -1);
|
||||
neu_adapter_driver_load_tag(driver, p->name, tag, 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -1379,6 +1379,28 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data)
|
||||
|
||||
break;
|
||||
}
|
||||
case NEU_REQ_ADD_GTAG: {
|
||||
neu_req_add_gtag_t *cmd = (neu_req_add_gtag_t *) &header[1];
|
||||
|
||||
if (neu_node_manager_find(manager->node_manager, header->receiver) ==
|
||||
NULL) {
|
||||
neu_resp_error_t e = { .error = NEU_ERR_NODE_NOT_EXIST };
|
||||
header->type = NEU_RESP_ERROR;
|
||||
neu_msg_exchange(header);
|
||||
reply(manager, header, &e);
|
||||
for (int i = 0; i < cmd->n_group; i++) {
|
||||
for (int j = 0; j < cmd->groups[i].n_tag; j++) {
|
||||
neu_tag_fini(&cmd->groups[i].tags[j]);
|
||||
}
|
||||
free(cmd->groups[i].tags);
|
||||
}
|
||||
free(cmd->groups);
|
||||
} else {
|
||||
forward_msg(manager, header, header->receiver);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case NEU_REQ_NODE_SETTING: {
|
||||
neu_req_node_setting_t *cmd = (neu_req_node_setting_t *) &header[1];
|
||||
|
||||
@@ -1396,6 +1418,7 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data)
|
||||
}
|
||||
|
||||
case NEU_RESP_ADD_TAG:
|
||||
case NEU_RESP_ADD_GTAG:
|
||||
case NEU_RESP_ADD_TEMPLATE_TAG:
|
||||
case NEU_RESP_UPDATE_TAG:
|
||||
case NEU_RESP_UPDATE_TEMPLATE_TAG:
|
||||
|
||||
@@ -536,7 +536,7 @@ static int add_template_group(neu_group_t *grp, void *data)
|
||||
break;
|
||||
}
|
||||
|
||||
ret = neu_adapter_driver_add_tag(driver, name, tag);
|
||||
ret = neu_adapter_driver_add_tag(driver, name, tag, -1);
|
||||
if (0 != ret) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -427,6 +427,213 @@ int neu_json_encode_au_tags_resp(void *json_object, void *param)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int neu_json_decode_gtag_json(void *json_obj, neu_json_gtag_t *gtag_p)
|
||||
{
|
||||
if (NULL == gtag_p) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
neu_json_elem_t gtag_elems[] = { {
|
||||
.name = "group",
|
||||
.t = NEU_JSON_STR,
|
||||
},
|
||||
{
|
||||
.name = "interval",
|
||||
.t = NEU_JSON_INT,
|
||||
},
|
||||
{
|
||||
.name = "tags",
|
||||
.t = NEU_JSON_OBJECT,
|
||||
} };
|
||||
|
||||
int ret = neu_json_decode_by_json(json_obj, NEU_JSON_ELEM_SIZE(gtag_elems),
|
||||
gtag_elems);
|
||||
|
||||
if (0 != ret) {
|
||||
goto decode_fail;
|
||||
}
|
||||
|
||||
neu_json_tag_array_t arr = { 0 };
|
||||
ret = neu_json_decode_tag_array_json(gtag_elems[2].v.val_object, &arr);
|
||||
if (ret != 0) {
|
||||
goto decode_fail;
|
||||
}
|
||||
if (arr.len <= 0) {
|
||||
goto decode_fail;
|
||||
}
|
||||
|
||||
gtag_p->group = gtag_elems[0].v.val_str;
|
||||
gtag_p->interval = gtag_elems[1].v.val_int;
|
||||
gtag_p->n_tag = arr.len;
|
||||
gtag_p->tags = arr.tags;
|
||||
|
||||
goto decode_exit;
|
||||
|
||||
decode_fail:
|
||||
free(gtag_p);
|
||||
free(gtag_elems[0].v.val_str);
|
||||
return -1;
|
||||
|
||||
decode_exit:
|
||||
if (json_obj != NULL) {
|
||||
neu_json_decode_free(json_obj);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void neu_json_decode_gtag_fini(neu_json_gtag_t *gtag)
|
||||
{
|
||||
free(gtag->group);
|
||||
for (int i = 0; i < gtag->n_tag; i++) {
|
||||
neu_json_decode_tag_fini(&(gtag->tags[i]));
|
||||
}
|
||||
free(gtag->tags);
|
||||
}
|
||||
|
||||
int neu_json_decode_gtag_array_json(void *json_obj, neu_json_gtag_array_t *arr)
|
||||
{
|
||||
int len = 0;
|
||||
neu_json_gtag_t *gtags = NULL;
|
||||
|
||||
if (!json_is_array((json_t *) json_obj)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = json_array_size(json_obj);
|
||||
if (0 == len) {
|
||||
arr->len = 0;
|
||||
arr->gtags = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
gtags = calloc(len, sizeof(*gtags));
|
||||
if (NULL == gtags) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
for (i = 0; i < len; i++) {
|
||||
json_t *tag_obj = json_array_get(json_obj, i);
|
||||
if (0 != neu_json_decode_gtag_json(tag_obj, >ags[i])) {
|
||||
goto decode_fail;
|
||||
}
|
||||
}
|
||||
|
||||
arr->len = len;
|
||||
arr->gtags = gtags;
|
||||
return 0;
|
||||
|
||||
decode_fail:
|
||||
while (--i > 0) {
|
||||
neu_json_decode_gtag_fini(>ags[i]);
|
||||
}
|
||||
free(gtags);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void neu_json_decode_gtag_array_fini(neu_json_gtag_array_t *arr)
|
||||
{
|
||||
for (int i = 0; i < arr->len; ++i) {
|
||||
neu_json_decode_gtag_fini(&arr->gtags[i]);
|
||||
}
|
||||
free(arr->gtags);
|
||||
}
|
||||
|
||||
int neu_json_decode_add_gtags_req(char *buf, neu_json_add_gtags_req_t **result)
|
||||
{
|
||||
int ret = 0;
|
||||
void * json_obj = NULL;
|
||||
neu_json_add_gtags_req_t *req = calloc(1, sizeof(neu_json_add_gtags_req_t));
|
||||
if (req == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
json_obj = neu_json_decode_new(buf);
|
||||
if (NULL == json_obj) {
|
||||
goto decode_fail;
|
||||
}
|
||||
|
||||
neu_json_elem_t req_elems[] = {
|
||||
{
|
||||
.name = "node",
|
||||
.t = NEU_JSON_STR,
|
||||
},
|
||||
{
|
||||
.name = "groups",
|
||||
.t = NEU_JSON_OBJECT,
|
||||
},
|
||||
};
|
||||
ret = neu_json_decode_by_json(json_obj, NEU_JSON_ELEM_SIZE(req_elems),
|
||||
req_elems);
|
||||
if (ret != 0) {
|
||||
goto decode_fail;
|
||||
}
|
||||
|
||||
neu_json_gtag_array_t arr = { 0 };
|
||||
ret = neu_json_decode_gtag_array_json(req_elems[1].v.val_object, &arr);
|
||||
if (ret != 0) {
|
||||
goto decode_fail;
|
||||
}
|
||||
if (arr.len <= 0) {
|
||||
goto decode_fail;
|
||||
}
|
||||
|
||||
req->node = req_elems[0].v.val_str;
|
||||
req->n_group = arr.len;
|
||||
req->groups = arr.gtags;
|
||||
*result = req;
|
||||
goto decode_exit;
|
||||
|
||||
decode_fail:
|
||||
free(req);
|
||||
free(req_elems[0].v.val_str);
|
||||
ret = -1;
|
||||
|
||||
decode_exit:
|
||||
if (json_obj != NULL) {
|
||||
neu_json_decode_free(json_obj);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void neu_json_decode_add_gtags_req_free(neu_json_add_gtags_req_t *req)
|
||||
{
|
||||
if (NULL == req) {
|
||||
return;
|
||||
}
|
||||
neu_json_gtag_array_t arr = {
|
||||
.len = req->n_group,
|
||||
.gtags = req->groups,
|
||||
};
|
||||
neu_json_decode_gtag_array_fini(&arr);
|
||||
|
||||
free(req->node);
|
||||
free(req);
|
||||
}
|
||||
|
||||
int neu_json_encode_au_gtags_resp(void *json_object, void *param)
|
||||
{
|
||||
int ret = 0;
|
||||
neu_json_add_gtag_res_t *resp = (neu_json_add_gtag_res_t *) param;
|
||||
neu_json_elem_t resp_elems[] = {
|
||||
{
|
||||
.name = "index",
|
||||
.t = NEU_JSON_INT,
|
||||
.v.val_int = resp->index,
|
||||
},
|
||||
{
|
||||
.name = "error",
|
||||
.t = NEU_JSON_INT,
|
||||
.v.val_int = resp->error,
|
||||
},
|
||||
};
|
||||
|
||||
ret = neu_json_encode_field(json_object, resp_elems,
|
||||
NEU_JSON_ELEM_SIZE(resp_elems));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int neu_json_encode_del_tags_req(void *json_object, void *param)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
@@ -75,6 +75,40 @@ typedef struct {
|
||||
|
||||
int neu_json_encode_au_tags_resp(void *json_object, void *param);
|
||||
|
||||
typedef struct {
|
||||
char * group;
|
||||
int n_tag;
|
||||
int interval;
|
||||
neu_json_tag_t *tags;
|
||||
} neu_json_gtag_t;
|
||||
|
||||
int neu_json_decode_gtag_json(void *json_obj, neu_json_gtag_t *gtag_p);
|
||||
void neu_json_decode_gtag_fini(neu_json_gtag_t *gtag);
|
||||
|
||||
typedef struct {
|
||||
int len;
|
||||
neu_json_gtag_t *gtags;
|
||||
} neu_json_gtag_array_t;
|
||||
|
||||
int neu_json_decode_gtag_array_json(void *json_obj, neu_json_gtag_array_t *arr);
|
||||
void neu_json_decode_gtag_array_fini(neu_json_gtag_array_t *arr);
|
||||
|
||||
typedef struct {
|
||||
char * node;
|
||||
int n_group;
|
||||
neu_json_gtag_t *groups;
|
||||
} neu_json_add_gtags_req_t;
|
||||
|
||||
int neu_json_decode_add_gtags_req(char *buf, neu_json_add_gtags_req_t **result);
|
||||
void neu_json_decode_add_gtags_req_free(neu_json_add_gtags_req_t *req);
|
||||
|
||||
typedef struct {
|
||||
uint16_t index;
|
||||
int error;
|
||||
} neu_json_add_gtag_res_t, neu_json_update_gtag_res_t;
|
||||
|
||||
int neu_json_encode_au_gtags_resp(void *json_object, void *param);
|
||||
|
||||
typedef char *neu_json_del_tags_req_name_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -110,11 +110,18 @@ def update_group(node, group, new_name="", interval=0):
|
||||
else:
|
||||
assert False
|
||||
|
||||
@gen_check
|
||||
def get_group():
|
||||
return requests.get(url=config.BASE_URL + '/api/v2/group', headers={"Authorization": config.default_jwt})
|
||||
|
||||
|
||||
@gen_check
|
||||
def add_tags(node, group, tags):
|
||||
return requests.post(url=config.BASE_URL + '/api/v2/tags', headers={"Authorization": config.default_jwt}, json={"node": node, "group": group, "tags": tags})
|
||||
|
||||
@gen_check
|
||||
def add_gtags(node, groups):
|
||||
return requests.post(url=config.BASE_URL + '/api/v2/gtags', headers={"Authorization": config.default_jwt}, json={"node": node, "groups": groups})
|
||||
|
||||
@gen_check
|
||||
def del_tags(node, group, tags):
|
||||
|
||||
@@ -52,4 +52,4 @@ def start_simulator(args, dir='build/simulator'):
|
||||
|
||||
|
||||
def stop_simulator(process):
|
||||
process.terminate()
|
||||
process.terminate()
|
||||
@@ -0,0 +1,3 @@
|
||||
import sys
|
||||
|
||||
sys.path.append("tests/ft")
|
||||
@@ -0,0 +1,358 @@
|
||||
import neuron.api as api
|
||||
from neuron.config import *
|
||||
from neuron.common import *
|
||||
from neuron.error import *
|
||||
|
||||
|
||||
class TestLog:
|
||||
|
||||
@description(given="multiple non-existing groups and multiple correct tags",
|
||||
when="adding",
|
||||
then="successfully added")
|
||||
def test_adding_correct_gtags_nonexisting_groups(self):
|
||||
response = api.add_node(node='modbus-tcp-tag-test', plugin=PLUGIN_MODBUS_TCP)
|
||||
assert 200 == response.status_code
|
||||
assert 0 == response.json()['error']
|
||||
|
||||
response = api.add_gtags(
|
||||
node='modbus-tcp-tag-test',
|
||||
groups=[
|
||||
{
|
||||
"group": "group_1",
|
||||
"interval": 3000,
|
||||
"tags": [
|
||||
{
|
||||
"name": "tag1",
|
||||
"address": "1!400001",
|
||||
"attribute": 3,
|
||||
"type": 3,
|
||||
"decimal": 0.01
|
||||
},
|
||||
{
|
||||
"name": "tag2",
|
||||
"address": "1!400002",
|
||||
"attribute": 3,
|
||||
"type": 9,
|
||||
"precision": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "group_2",
|
||||
"interval": 300,
|
||||
"tags": [
|
||||
{
|
||||
"name": "tag1",
|
||||
"address": "1!400003",
|
||||
"attribute": 3,
|
||||
"type": 9,
|
||||
"precision": 3
|
||||
},
|
||||
{
|
||||
"name": "tag2",
|
||||
"address": "1!400004",
|
||||
"attribute": 3,
|
||||
"type": 9,
|
||||
"precision": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
assert 200 == response.status_code
|
||||
assert NEU_ERR_SUCCESS == response.json()['error']
|
||||
|
||||
response = api.get_group()
|
||||
assert 200 == response.status_code
|
||||
assert 'group_1' == response.json()['groups'][0]['group']
|
||||
assert 3000 == response.json()['groups'][0]['interval']
|
||||
assert 2 == response.json()['groups'][0]['tag_count']
|
||||
assert 'group_2' == response.json()['groups'][1]['group']
|
||||
assert 300 == response.json()['groups'][1]['interval']
|
||||
assert 2 == response.json()['groups'][1]['tag_count']
|
||||
|
||||
response = api.get_tags(node='modbus-tcp-tag-test', group='group_1')
|
||||
assert 200 == response.status_code
|
||||
assert 'tag1' == response.json()['tags'][0]['name']
|
||||
assert '1!400001' == response.json()['tags'][0]['address']
|
||||
assert 0.01 == response.json()['tags'][0]['decimal']
|
||||
assert 3 == response.json()['tags'][0]['type']
|
||||
assert 3 == response.json()['tags'][0]['attribute']
|
||||
|
||||
response = api.get_tags(node='modbus-tcp-tag-test', group='group_1')
|
||||
assert 200 == response.status_code
|
||||
assert 'tag2' == response.json()['tags'][1]['name']
|
||||
assert '1!400002' == response.json()['tags'][1]['address']
|
||||
assert 3 == response.json()['tags'][1]['precision']
|
||||
assert 9 == response.json()['tags'][1]['type']
|
||||
assert 3 == response.json()['tags'][1]['attribute']
|
||||
|
||||
response = api.get_tags(node='modbus-tcp-tag-test', group='group_2')
|
||||
assert 200 == response.status_code
|
||||
assert 'tag1' == response.json()['tags'][0]['name']
|
||||
assert '1!400003' == response.json()['tags'][0]['address']
|
||||
assert 3 == response.json()['tags'][1]['precision']
|
||||
assert 9 == response.json()['tags'][1]['type']
|
||||
assert 3 == response.json()['tags'][1]['attribute']
|
||||
|
||||
response = api.get_tags(node='modbus-tcp-tag-test', group='group_2')
|
||||
assert 200 == response.status_code
|
||||
assert 'tag2' == response.json()['tags'][1]['name']
|
||||
assert '1!400004' == response.json()['tags'][1]['address']
|
||||
assert 3 == response.json()['tags'][1]['precision']
|
||||
assert 9 == response.json()['tags'][1]['type']
|
||||
assert 3 == response.json()['tags'][1]['attribute']
|
||||
|
||||
@description(given="multiple groups including partly existing ones and multiple correct tags", when="adding", then="successfully added")
|
||||
def test_adding_correct_gtags_existing_groups(self):
|
||||
response = api.add_gtags(
|
||||
node='modbus-tcp-tag-test',
|
||||
groups=[
|
||||
{
|
||||
"group": "group_1",
|
||||
"interval": 3000,
|
||||
"tags": [
|
||||
{
|
||||
"name": "tag3",
|
||||
"address": "1!400005",
|
||||
"attribute": 3,
|
||||
"type": 3,
|
||||
"decimal": 0.01
|
||||
},
|
||||
{
|
||||
"name": "tag4",
|
||||
"address": "1!400006",
|
||||
"attribute": 3,
|
||||
"type": 9,
|
||||
"precision": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "group_3",
|
||||
"interval": 3000,
|
||||
"tags": [
|
||||
{
|
||||
"name": "tag1",
|
||||
"address": "1!400007",
|
||||
"attribute": 3,
|
||||
"type": 9,
|
||||
"precision": 3
|
||||
},
|
||||
{
|
||||
"name": "tag2",
|
||||
"address": "1!400008",
|
||||
"attribute": 3,
|
||||
"type": 9,
|
||||
"precision": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
assert 200 == response.status_code
|
||||
assert NEU_ERR_SUCCESS == response.json()['error']
|
||||
|
||||
response = api.get_group()
|
||||
assert 200 == response.status_code
|
||||
assert 'group_1' == response.json()['groups'][0]['group']
|
||||
assert 3000 == response.json()['groups'][0]['interval']
|
||||
assert 4 == response.json()['groups'][0]['tag_count']
|
||||
assert 'group_2' == response.json()['groups'][1]['group']
|
||||
assert 300 == response.json()['groups'][1]['interval']
|
||||
assert 2 == response.json()['groups'][1]['tag_count']
|
||||
assert 'group_3' == response.json()['groups'][2]['group']
|
||||
assert 3000 == response.json()['groups'][2]['interval']
|
||||
assert 2 == response.json()['groups'][2]['tag_count']
|
||||
|
||||
response = api.get_tags(node='modbus-tcp-tag-test', group='group_1')
|
||||
assert 200 == response.status_code
|
||||
assert 'tag1' == response.json()['tags'][0]['name']
|
||||
assert '1!400001' == response.json()['tags'][0]['address']
|
||||
assert 0.01 == response.json()['tags'][0]['decimal']
|
||||
assert 3 == response.json()['tags'][0]['type']
|
||||
assert 3 == response.json()['tags'][0]['attribute']
|
||||
|
||||
response = api.get_tags(node='modbus-tcp-tag-test', group='group_1')
|
||||
assert 200 == response.status_code
|
||||
assert 'tag2' == response.json()['tags'][1]['name']
|
||||
assert '1!400002' == response.json()['tags'][1]['address']
|
||||
assert 3 == response.json()['tags'][1]['precision']
|
||||
assert 9 == response.json()['tags'][1]['type']
|
||||
assert 3 == response.json()['tags'][1]['attribute']
|
||||
|
||||
response = api.get_tags(node='modbus-tcp-tag-test', group='group_1')
|
||||
assert 200 == response.status_code
|
||||
assert 'tag3' == response.json()['tags'][2]['name']
|
||||
assert '1!400005' == response.json()['tags'][2]['address']
|
||||
assert 0.01 == response.json()['tags'][2]['decimal']
|
||||
assert 3 == response.json()['tags'][2]['type']
|
||||
assert 3 == response.json()['tags'][2]['attribute']
|
||||
|
||||
response = api.get_tags(node='modbus-tcp-tag-test', group='group_1')
|
||||
assert 200 == response.status_code
|
||||
assert 'tag4' == response.json()['tags'][3]['name']
|
||||
assert '1!400006' == response.json()['tags'][3]['address']
|
||||
assert 3 == response.json()['tags'][3]['precision']
|
||||
assert 9 == response.json()['tags'][3]['type']
|
||||
assert 3 == response.json()['tags'][3]['attribute']
|
||||
|
||||
response = api.get_tags(node='modbus-tcp-tag-test', group='group_2')
|
||||
assert 200 == response.status_code
|
||||
assert 'tag1' == response.json()['tags'][0]['name']
|
||||
assert '1!400003' == response.json()['tags'][0]['address']
|
||||
assert 3 == response.json()['tags'][1]['precision']
|
||||
assert 9 == response.json()['tags'][1]['type']
|
||||
assert 3 == response.json()['tags'][1]['attribute']
|
||||
|
||||
response = api.get_tags(node='modbus-tcp-tag-test', group='group_2')
|
||||
assert 200 == response.status_code
|
||||
assert 'tag2' == response.json()['tags'][1]['name']
|
||||
assert '1!400004' == response.json()['tags'][1]['address']
|
||||
assert 3 == response.json()['tags'][1]['precision']
|
||||
assert 9 == response.json()['tags'][1]['type']
|
||||
assert 3 == response.json()['tags'][1]['attribute']
|
||||
|
||||
response = api.get_tags(node='modbus-tcp-tag-test', group='group_3')
|
||||
assert 200 == response.status_code
|
||||
assert 'tag1' == response.json()['tags'][0]['name']
|
||||
assert '1!400007' == response.json()['tags'][0]['address']
|
||||
assert 3 == response.json()['tags'][1]['precision']
|
||||
assert 9 == response.json()['tags'][1]['type']
|
||||
assert 3 == response.json()['tags'][1]['attribute']
|
||||
|
||||
response = api.get_tags(node='modbus-tcp-tag-test', group='group_3')
|
||||
assert 200 == response.status_code
|
||||
assert 'tag2' == response.json()['tags'][1]['name']
|
||||
assert '1!400008' == response.json()['tags'][1]['address']
|
||||
assert 3 == response.json()['tags'][1]['precision']
|
||||
assert 9 == response.json()['tags'][1]['type']
|
||||
assert 3 == response.json()['tags'][1]['attribute']
|
||||
|
||||
@description(given="multiple groups and tags with errors", when="adding", then="error reported, unable to add")
|
||||
def test_adding_gtags_type_err(self):
|
||||
response = api.add_gtags(
|
||||
node='modbus-tcp-tag-test',
|
||||
groups=[
|
||||
{
|
||||
"group": "group_4",
|
||||
"interval": 3000,
|
||||
"tags": [
|
||||
{
|
||||
"name": "tag1",
|
||||
"address": "1!000009",
|
||||
"attribute": 3,
|
||||
"type": 3,
|
||||
"decimal": 0.01
|
||||
},
|
||||
{
|
||||
"name": "tag4",
|
||||
"address": "1!400010",
|
||||
"attribute": 3,
|
||||
"type": 9,
|
||||
"precision": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "group_5",
|
||||
"interval": 3000,
|
||||
"tags": [
|
||||
{
|
||||
"name": "tag1",
|
||||
"address": "1!400011",
|
||||
"attribute": 3,
|
||||
"type": 9,
|
||||
"precision": 3
|
||||
},
|
||||
{
|
||||
"name": "tag2",
|
||||
"address": "1!400012",
|
||||
"attribute": 3,
|
||||
"type": 9,
|
||||
"precision": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
assert 200 == response.status_code
|
||||
assert NEU_ERR_TAG_TYPE_NOT_SUPPORT == response.json()['error']
|
||||
|
||||
response = api.get_group()
|
||||
assert 200 == response.status_code
|
||||
assert 'group_1' == response.json()['groups'][0]['group']
|
||||
assert 3000 == response.json()['groups'][0]['interval']
|
||||
assert 4 == response.json()['groups'][0]['tag_count']
|
||||
assert 'group_2' == response.json()['groups'][1]['group']
|
||||
assert 300 == response.json()['groups'][1]['interval']
|
||||
assert 2 == response.json()['groups'][1]['tag_count']
|
||||
assert 'group_3' == response.json()['groups'][2]['group']
|
||||
assert 3000 == response.json()['groups'][2]['interval']
|
||||
assert 2 == response.json()['groups'][2]['tag_count']
|
||||
|
||||
@description(given="multiple groups and conflicting tag names", when="adding", then="error reported, unable to add")
|
||||
def test_adding_gtags_name_err(self):
|
||||
response = api.add_gtags(
|
||||
node='modbus-tcp-tag-test',
|
||||
groups=[
|
||||
{
|
||||
"group": "group_1",
|
||||
"interval": 3000,
|
||||
"tags": [
|
||||
{
|
||||
"name": "tag1",
|
||||
"address": "1!400001",
|
||||
"attribute": 3,
|
||||
"type": 3,
|
||||
"decimal": 0.01
|
||||
},
|
||||
{
|
||||
"name": "tag2",
|
||||
"address": "1!400002",
|
||||
"attribute": 3,
|
||||
"type": 9,
|
||||
"precision": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "group_2",
|
||||
"interval": 3000,
|
||||
"tags": [
|
||||
{
|
||||
"name": "tag1",
|
||||
"address": "1!400003",
|
||||
"attribute": 3,
|
||||
"type": 9,
|
||||
"precision": 3
|
||||
},
|
||||
{
|
||||
"name": "tag2",
|
||||
"address": "1!400004",
|
||||
"attribute": 3,
|
||||
"type": 9,
|
||||
"precision": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
assert 200 == response.status_code
|
||||
assert NEU_ERR_TAG_NAME_CONFLICT == response.json()['error']
|
||||
|
||||
response = api.get_group()
|
||||
assert 200 == response.status_code
|
||||
assert 'group_1' == response.json()['groups'][0]['group']
|
||||
assert 3000 == response.json()['groups'][0]['interval']
|
||||
assert 4 == response.json()['groups'][0]['tag_count']
|
||||
assert 'group_2' == response.json()['groups'][1]['group']
|
||||
assert 300 == response.json()['groups'][1]['interval']
|
||||
assert 2 == response.json()['groups'][1]['tag_count']
|
||||
assert 'group_3' == response.json()['groups'][2]['group']
|
||||
assert 3000 == response.json()['groups'][2]['interval']
|
||||
assert 2 == response.json()['groups'][2]['tag_count']
|
||||
Reference in New Issue
Block a user