diff --git a/include/neuron/msg.h b/include/neuron/msg.h index e145fb03..a2ccd1e6 100644 --- a/include/neuron/msg.h +++ b/include/neuron/msg.h @@ -36,7 +36,7 @@ extern "C" { typedef struct { neu_node_running_state_e running; neu_node_link_state_e link; - char log_level[NEU_LOG_LEVEL_LEN]; + int log_level; } neu_node_state_t; typedef enum neu_reqresp_type { @@ -624,7 +624,9 @@ typedef struct neu_req_get_node_state { typedef struct neu_resp_get_node_state { neu_node_state_t state; uint16_t rtt; // round trip time in milliseconds - char core_level[NEU_LOG_LEVEL_LEN]; + int core_level; + uint16_t sub_group_count; + bool is_driver; } neu_resp_get_node_state_t; typedef struct neu_req_get_nodes_state { @@ -634,6 +636,8 @@ typedef struct { char node[NEU_NODE_NAME_LEN]; neu_node_state_t state; uint16_t rtt; // round trip time in milliseconds + uint16_t sub_group_count; + bool is_driver; } neu_nodes_state_t; inline static UT_icd neu_nodes_state_t_icd() @@ -644,7 +648,7 @@ inline static UT_icd neu_nodes_state_t_icd() } typedef struct { UT_array *states; // array of neu_nodes_state_t - char core_level[NEU_LOG_LEVEL_LEN]; + int core_level; } neu_resp_get_nodes_state_t, neu_reqresp_nodes_state_t; typedef struct { @@ -1086,7 +1090,7 @@ typedef struct { typedef struct neu_req_update_log_level { char node[NEU_NODE_NAME_LEN]; - char log_level[NEU_LOG_LEVEL_LEN]; + int log_level; bool core; } neu_req_update_log_level_t; diff --git a/include/neuron/utils/log.h b/include/neuron/utils/log.h index 3969138e..d1efff57 100644 --- a/include/neuron/utils/log.h +++ b/include/neuron/utils/log.h @@ -25,8 +25,32 @@ config_ **/ #include "utils/zlog.h" +#include "define.h" + extern zlog_category_t *neuron; +inline static const char *log_level_to_str(int level) +{ + switch (level) { + case ZLOG_LEVEL_FATAL: + return NEU_LOG_LEVEL_FATAL; + case ZLOG_LEVEL_ERROR: + return NEU_LOG_LEVEL_ERROR; + case ZLOG_LEVEL_WARN: + return NEU_LOG_LEVEL_WARN; + case ZLOG_LEVEL_NOTICE: + return NEU_LOG_LEVEL_NOTICE; + case ZLOG_LEVEL_INFO: + return NEU_LOG_LEVEL_INFO; + case ZLOG_LEVEL_DEBUG: + return NEU_LOG_LEVEL_DEBUG; + default: + return "UNKNOWN"; + } +} + +#define nlog_level_change(level) zlog_level_switch(neuron, level) + #define nlog_fatal(...) \ zlog(neuron, __FILE__, sizeof(__FILE__) - 1, __func__, \ sizeof(__func__) - 1, __LINE__, ZLOG_LEVEL_FATAL, __VA_ARGS__) diff --git a/plugins/restful/adapter_handle.c b/plugins/restful/adapter_handle.c index 2ca0249c..a45651b9 100644 --- a/plugins/restful/adapter_handle.c +++ b/plugins/restful/adapter_handle.c @@ -330,11 +330,13 @@ void handle_get_node_state_resp(nng_aio *aio, neu_resp_get_node_state_t *state) neu_json_get_node_state_resp_t res = { 0 }; char * result = NULL; - res.link = state->state.link; - res.running = state->state.running; - res.rtt = state->rtt; - res.log_level = state->state.log_level; - strcpy(res.core_level, state->core_level); + res.link = state->state.link; + res.running = state->state.running; + res.rtt = state->rtt; + res.sub_group_count = state->sub_group_count; + res.is_driver = state->is_driver; + res.log_level = (char *) log_level_to_str(state->state.log_level); + res.core_level = (char *) log_level_to_str(state->core_level); neu_json_encode_by_fn(&res, neu_json_encode_get_node_state_resp, &result); @@ -359,10 +361,13 @@ void handle_get_nodes_state_resp(nng_aio * aio, states_res.nodes[index].running = state->state.running; states_res.nodes[index].link = state->state.link; states_res.nodes[index].rtt = state->rtt; - states_res.nodes[index].log_level = state->state.log_level; + states_res.nodes[index].sub_group_count = state->sub_group_count; + states_res.nodes[index].is_driver = state->is_driver; + states_res.nodes[index].log_level = + (char *) log_level_to_str(state->state.log_level); } - strcpy(states_res.core_level, states->core_level); + states_res.core_level = (char *) log_level_to_str(states->core_level); neu_json_encode_by_fn(&states_res, neu_json_encode_get_nodes_state_resp, &result); diff --git a/plugins/restful/log_handle.c b/plugins/restful/log_handle.c index d675f094..6b7c674e 100644 --- a/plugins/restful/log_handle.c +++ b/plugins/restful/log_handle.c @@ -113,78 +113,48 @@ void handle_log_level(nng_aio *aio) NEU_PROCESS_HTTP_REQUEST_VALIDATE_JWT( aio, neu_json_update_log_level_req_t, neu_json_decode_update_log_level_req, { - int ret = 0; - neu_reqresp_head_t header = { 0 }; - neu_req_update_log_level_t cmd = { 0 }; - int log_level; + neu_reqresp_head_t header = { 0 }; + neu_req_update_log_level_t cmd = { 0 }; + int log_level = -1; if (0 == strcmp(req->log_level, NEU_LOG_LEVEL_DEBUG)) { log_level = ZLOG_LEVEL_DEBUG; - strcpy(cmd.log_level, NEU_LOG_LEVEL_DEBUG); } else if (0 == strcmp(req->log_level, NEU_LOG_LEVEL_INFO)) { log_level = ZLOG_LEVEL_INFO; - strcpy(cmd.log_level, NEU_LOG_LEVEL_INFO); } else if (0 == strcmp(req->log_level, NEU_LOG_LEVEL_NOTICE)) { log_level = ZLOG_LEVEL_NOTICE; - strcpy(cmd.log_level, NEU_LOG_LEVEL_NOTICE); } else if (0 == strcmp(req->log_level, NEU_LOG_LEVEL_WARN)) { log_level = ZLOG_LEVEL_WARN; - strcpy(cmd.log_level, NEU_LOG_LEVEL_WARN); } else if (0 == strcmp(req->log_level, NEU_LOG_LEVEL_ERROR)) { log_level = ZLOG_LEVEL_ERROR; - strcpy(cmd.log_level, NEU_LOG_LEVEL_ERROR); } else if (0 == strcmp(req->log_level, NEU_LOG_LEVEL_FATAL)) { log_level = ZLOG_LEVEL_FATAL; - strcpy(cmd.log_level, NEU_LOG_LEVEL_FATAL); } else { - strcpy(cmd.log_level, "unknow"); - nlog_error( - "Failed to modify log_level of the node, node_name:%s, ", - req->node_name); + nlog_error("Failed to modify log_level of the node, " + "node_name:%s, log_level: %s", + req->node_name, req->log_level); + } + + if (log_level == -1) { NEU_JSON_RESPONSE_ERROR(NEU_ERR_PARAM_IS_WRONG, { neu_http_response(aio, error_code.error, result_error); }); - goto end; - } - if (req->core) { - zlog_category_t *neuron = zlog_get_category("neuron"); - ret = zlog_level_switch(neuron, log_level); + } else { + header.ctx = aio; + header.type = NEU_REQ_UPDATE_LOG_LEVEL; + cmd.core = req->core; + cmd.log_level = log_level; + if (req->node_name != NULL) { + strcpy(cmd.node, req->node_name); + } + + int ret = neu_plugin_op(plugin, header, &cmd); if (ret != 0) { - nlog_error( - "Failed to modify log_level of the core, ret: %d", ret); - NEU_JSON_RESPONSE_ERROR(NEU_ERR_EINTERNAL, { - neu_http_response(aio, error_code.error, result_error); + NEU_JSON_RESPONSE_ERROR(NEU_ERR_IS_BUSY, { + neu_http_response(aio, NEU_ERR_IS_BUSY, result_error); }); - goto end; } } - - if (req->node_name) { - zlog_category_t *ct = zlog_get_category(req->node_name); - strcpy(cmd.node, req->node_name); - ret = zlog_level_switch(ct, log_level); - if (ret != 0) { - nlog_error( - "Failed to modify log_level of the node, node_name:%s, " - "ret: %d,", - req->node_name, ret); - NEU_JSON_RESPONSE_ERROR(0, { - neu_http_response(aio, error_code.error, result_error); - }); - goto end; - } - } - - header.ctx = aio; - header.type = NEU_REQ_UPDATE_LOG_LEVEL; - cmd.core = req->core; - 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); - }); - } - end:; }) } diff --git a/src/adapter/adapter.c b/src/adapter/adapter.c index 789e5ad4..8231746b 100644 --- a/src/adapter/adapter.c +++ b/src/adapter/adapter.c @@ -147,6 +147,7 @@ neu_adapter_t *neu_adapter_create(neu_adapter_info_t *info, bool load) adapter->module = info->module; adapter->timestamp_lev = 0; adapter->trans_data_port = 0; + adapter->log_level = ZLOG_LEVEL_NOTICE; struct sockaddr_in remote = { .sin_family = AF_INET, @@ -487,9 +488,7 @@ static int adapter_command(neu_adapter_t *adapter, neu_reqresp_head_t header, } case NEU_REQ_UPDATE_LOG_LEVEL: { neu_req_update_log_level_t *cmd = (neu_req_update_log_level_t *) data; - if (cmd->node != NULL) { - strcpy(pheader->receiver, cmd->node); - } + strcpy(pheader->receiver, cmd->node); break; } default: @@ -1234,7 +1233,12 @@ static int adapter_loop(enum neu_event_io_type type, int fd, void *usr_data) break; } case NEU_REQ_UPDATE_LOG_LEVEL: { + neu_req_update_log_level_t *cmd = + (neu_req_update_log_level_t *) &header[1]; neu_resp_error_t error = { 0 }; + adapter->log_level = cmd->log_level; + zlog_level_switch(neu_plugin_to_plugin_common(adapter->plugin)->log, + cmd->log_level); struct timeval tv = { 0 }; gettimeofday(&tv, NULL); @@ -1426,9 +1430,9 @@ neu_node_state_t neu_adapter_get_state(neu_adapter_t *adapter) neu_node_state_t state = { 0 }; neu_plugin_common_t *common = neu_plugin_to_plugin_common(adapter->plugin); - state.link = common->link_state; - state.running = adapter->state; - strcpy(state.log_level, common->log_level); + state.link = common->link_state; + state.running = adapter->state; + state.log_level = adapter->log_level; return state; } diff --git a/src/adapter/adapter_internal.h b/src/adapter/adapter_internal.h index d9616b0e..7fc9ab5c 100644 --- a/src/adapter/adapter_internal.h +++ b/src/adapter/adapter_internal.h @@ -33,8 +33,6 @@ struct neu_adapter { neu_node_running_state_e state; - char log_level[NEU_LOG_LEVEL_LEN]; - adapter_callbacks_t cb_funs; void * handle; @@ -59,6 +57,7 @@ struct neu_adapter { // metrics neu_node_metrics_t *metrics; + int log_level; }; typedef void (*adapter_handler)(neu_adapter_t * adapter, diff --git a/src/base/neu_plugin_common.c b/src/base/neu_plugin_common.c index 781b61a7..5616d05e 100644 --- a/src/base/neu_plugin_common.c +++ b/src/base/neu_plugin_common.c @@ -31,7 +31,6 @@ void neu_plugin_common_init(neu_plugin_common_t *common) { common->magic = NEU_PLUGIN_MAGIC_NUMBER; common->link_state = NEU_NODE_LINK_STATE_DISCONNECTED; - strcpy(common->log_level, NEU_LOG_LEVEL_NOTICE); } bool neu_plugin_common_check(neu_plugin_t *plugin) diff --git a/src/core/manager.c b/src/core/manager.c index de8dca3f..7bc60fc1 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -101,6 +101,7 @@ neu_manager_t *neu_manager_create() manager->node_manager = neu_node_manager_create(); manager->subscribe_manager = neu_subscribe_manager_create(); manager->template_manager = neu_template_manager_create(); + manager->log_level = ZLOG_LEVEL_NOTICE; manager->server_fd = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP); @@ -1160,12 +1161,14 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data) case NEU_REQ_GET_NODES_STATE: { neu_resp_get_nodes_state_t resp = { 0 }; UT_array *states = neu_node_manager_get_state(manager->node_manager); - - neu_adapter_t *adapter_core = - neu_node_manager_find(manager->node_manager, "default-dashboard"); - strcpy(resp.core_level, - neu_plugin_to_plugin_common(adapter_core->plugin)->log_level); - resp.states = utarray_clone(states); + neu_nodes_state_t *p_state = NULL; + while ( + (p_state = (neu_nodes_state_t *) utarray_next(states, p_state))) { + p_state->sub_group_count = neu_subscribe_manager_group_count( + manager->subscribe_manager, p_state->node); + } + resp.states = utarray_clone(states); + resp.core_level = manager->log_level; strcpy(header->receiver, header->sender); strcpy(header->sender, "manager"); @@ -1219,13 +1222,6 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data) neu_msg_exchange(header); reply(manager, header, &e); } else { - neu_resp_get_node_state_t *resp = - (neu_resp_get_node_state_t *) &header[1]; - neu_adapter_t *adapter_core = neu_node_manager_find( - manager->node_manager, "default-dashboard"); - strcpy( - resp->core_level, - neu_plugin_to_plugin_common(adapter_core->plugin)->log_level); forward_msg(manager, header, header->receiver); } @@ -1427,12 +1423,26 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data) case NEU_RESP_GET_NDRIVER_TAGS: case NEU_RESP_GET_GROUP: case NEU_RESP_GET_NODE_SETTING: - case NEU_RESP_GET_NODE_STATE: case NEU_RESP_ERROR: case NEU_RESP_READ_GROUP: forward_msg(manager, header, header->receiver); break; + case NEU_RESP_GET_NODE_STATE: { + neu_resp_get_node_state_t *resp = + (neu_resp_get_node_state_t *) &header[1]; + + neu_adapter_t *adapter_node = + neu_node_manager_find(manager->node_manager, header->sender); + resp->sub_group_count = neu_subscribe_manager_group_count( + manager->subscribe_manager, header->sender); + resp->is_driver = + (adapter_node->module->type == NEU_NA_TYPE_DRIVER) ? true : false; + resp->core_level = manager->log_level; + + forward_msg(manager, header, header->receiver); + break; + } case NEU_REQ_ADD_NDRIVER_MAP: { neu_req_ndriver_map_t *cmd = (neu_req_ndriver_map_t *) &header[1]; neu_resp_error_t error = { 0 }; @@ -1514,58 +1524,31 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data) (neu_req_update_log_level_t *) &header[1]; if (cmd->core) { - if (strcmp(header->receiver, "") == 0) { - neu_adapter_t *adapter_core = neu_node_manager_find( - manager->node_manager, "default-dashboard"); - strcpy(neu_plugin_to_plugin_common(adapter_core->plugin) - ->log_level, - cmd->log_level); - neu_resp_error_t error = { 0 }; - neu_msg_exchange(header); - header->type = NEU_RESP_ERROR; - reply(manager, header, &error); - } else { - 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); - } else { - neu_adapter_t *adapter_core = neu_node_manager_find( - manager->node_manager, "default-dashboard"); - strcpy(neu_plugin_to_plugin_common(adapter_core->plugin) - ->log_level, - cmd->log_level); - neu_adapter_t *adapter_log = neu_node_manager_find( - manager->node_manager, header->receiver); - strcpy(neu_plugin_to_plugin_common(adapter_log->plugin) - ->log_level, - cmd->log_level); - forward_msg(manager, header, header->receiver); - } - } - } else { - if (strcmp(header->receiver, "") == 0) { - neu_resp_error_t e = { .error = NEU_ERR_PARAM_IS_WRONG }; + manager->log_level = cmd->log_level; + nlog_level_change(manager->log_level); + } + + if (strlen(cmd->node) > 0) { + 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); } else { - 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); - } else { - neu_adapter_t *adapter_log = neu_node_manager_find( - manager->node_manager, header->receiver); - strcpy(neu_plugin_to_plugin_common(adapter_log->plugin) - ->log_level, - cmd->log_level); - forward_msg(manager, header, header->receiver); - } + forward_msg(manager, header, header->receiver); + } + } else { + if (cmd->core) { + neu_resp_error_t e = { .error = NEU_ERR_SUCCESS }; + header->type = NEU_RESP_ERROR; + neu_msg_exchange(header); + reply(manager, header, &e); + } else { + neu_resp_error_t e = { .error = NEU_ERR_PARAM_IS_WRONG }; + header->type = NEU_RESP_ERROR; + neu_msg_exchange(header); + reply(manager, header, &e); } } diff --git a/src/core/manager_internal.h b/src/core/manager_internal.h index 874ce1d1..ea39d136 100644 --- a/src/core/manager_internal.h +++ b/src/core/manager_internal.h @@ -29,9 +29,10 @@ #include "template_manager.h" typedef struct neu_manager { - int server_fd; - uint8_t buf[NEU_MSG_MAX_SIZE]; - uint8_t recv_buf[NEU_MSG_MAX_SIZE]; + int server_fd; + uint8_t buf[NEU_MSG_MAX_SIZE]; + uint8_t recv_buf[NEU_MSG_MAX_SIZE]; + neu_events_t * events; neu_event_io_t *loop; @@ -43,6 +44,8 @@ typedef struct neu_manager { neu_event_timer_t *timer_timestamp; int64_t timestamp_lev_manager; + + int log_level; } neu_manager_t; int neu_manager_add_plugin(neu_manager_t *manager, const char *library); diff --git a/src/core/node_manager.c b/src/core/node_manager.c index 78ecca9f..17a4d9b8 100644 --- a/src/core/node_manager.c +++ b/src/core/node_manager.c @@ -414,8 +414,10 @@ UT_array *neu_node_manager_get_state(neu_node_manager_t *mgr) state.state.running = el->adapter->state; state.state.link = neu_plugin_to_plugin_common(el->adapter->plugin)->link_state; - strcpy(state.state.log_level, - neu_plugin_to_plugin_common(el->adapter->plugin)->log_level); + state.state.log_level = el->adapter->log_level; + state.is_driver = (el->adapter->module->type == NEU_NA_TYPE_DRIVER) + ? true + : false; neu_metric_entry_t *e = NULL; if (NULL != el->adapter->metrics) { HASH_FIND_STR(el->adapter->metrics->entries, diff --git a/src/core/subscribe.c b/src/core/subscribe.c index df38ce96..33512bef 100644 --- a/src/core/subscribe.c +++ b/src/core/subscribe.c @@ -132,6 +132,25 @@ UT_array *neu_subscribe_manager_get(neu_subscribe_mgr_t *mgr, const char *app) return groups; } +size_t neu_subscribe_manager_group_count(const neu_subscribe_mgr_t *mgr, + const char * app) +{ + size_t group_count = 0; + sub_elem_t *current_element, *tmp; + + HASH_ITER(hh, mgr->ss, current_element, tmp) + { + utarray_foreach(current_element->apps, neu_app_subscribe_t *, sub_app) + { + if (strcmp(sub_app->app_name, app) == 0) { + group_count++; + } + } + } + + return group_count; +} + UT_array *neu_subscribe_manager_get_ndriver_maps(neu_subscribe_mgr_t *mgr, const char * ndriver) { diff --git a/src/core/subscribe.h b/src/core/subscribe.h index bb8bacb3..127e4f42 100644 --- a/src/core/subscribe.h +++ b/src/core/subscribe.h @@ -48,6 +48,8 @@ UT_array *neu_subscribe_manager_find(neu_subscribe_mgr_t *mgr, UT_array *neu_subscribe_manager_find_by_driver(neu_subscribe_mgr_t *mgr, const char * driver); UT_array *neu_subscribe_manager_get(neu_subscribe_mgr_t *mgr, const char *app); +size_t neu_subscribe_manager_group_count(const neu_subscribe_mgr_t *mgr, + const char * app); UT_array *neu_subscribe_manager_get_ndriver_maps(neu_subscribe_mgr_t *mgr, const char * ndriver); void neu_subscribe_manager_unsub_all(neu_subscribe_mgr_t *mgr, const char *app); diff --git a/src/parser/neu_json_node.c b/src/parser/neu_json_node.c index 52ebfa4f..943eebcd 100644 --- a/src/parser/neu_json_node.c +++ b/src/parser/neu_json_node.c @@ -169,6 +169,7 @@ int neu_json_encode_get_node_state_resp(void *json_object, void *param) int ret = 0; neu_json_get_node_state_resp_t *resp = (neu_json_get_node_state_resp_t *) param; + int array_size = resp->is_driver ? 5 : 6; neu_json_elem_t resp_elems[] = { { .name = "running", @@ -194,9 +195,14 @@ int neu_json_encode_get_node_state_resp(void *json_object, void *param) .name = "neuron_core", .t = NEU_JSON_STR, .v.val_str = resp->core_level, + }, + { + .name = "sub_group_count", + .t = NEU_JSON_INT, + .v.val_int = resp->sub_group_count, } }; - ret = neu_json_encode_field(json_object, resp_elems, - NEU_JSON_ELEM_SIZE(resp_elems)); + + ret = neu_json_encode_field(json_object, resp_elems, array_size); return ret; } @@ -210,6 +216,7 @@ int neu_json_encode_get_nodes_state_resp(void *json_object, void *param) void * node_array = neu_json_array(); neu_json_get_nodes_state_t *p_node = resp->nodes; for (int i = 0; i < resp->n_node; i++) { + int array_size = p_node->is_driver ? 5 : 6; neu_json_elem_t node_elems[] = { { .name = "node", .t = NEU_JSON_STR, @@ -234,9 +241,15 @@ int neu_json_encode_get_nodes_state_resp(void *json_object, void *param) .name = "log_level", .t = NEU_JSON_STR, .v.val_str = p_node->log_level, + }, + { + .name = "sub_group_count", + .t = NEU_JSON_INT, + .v.val_int = + p_node->sub_group_count, } }; - node_array = neu_json_encode_array(node_array, node_elems, - NEU_JSON_ELEM_SIZE(node_elems)); + + node_array = neu_json_encode_array(node_array, node_elems, array_size); p_node++; } diff --git a/src/parser/neu_json_node.h b/src/parser/neu_json_node.h index e3268701..478527d0 100644 --- a/src/parser/neu_json_node.h +++ b/src/parser/neu_json_node.h @@ -50,27 +50,31 @@ int neu_json_decode_del_node_req(char *buf, neu_json_del_node_req_t **result); void neu_json_decode_del_node_req_free(neu_json_del_node_req_t *req); typedef struct { - int64_t running; - int64_t link; - int64_t rtt; - char * log_level; - char core_level[NEU_LOG_LEVEL_LEN]; + int64_t running; + int64_t link; + int64_t rtt; + uint16_t sub_group_count; + bool is_driver; + char * log_level; + char * core_level; } neu_json_get_node_state_resp_t; int neu_json_encode_get_node_state_resp(void *json_object, void *param); typedef struct { - char * name; - int64_t running; - int64_t link; - int64_t rtt; - char * log_level; + char * name; + int64_t running; + int64_t link; + int64_t rtt; + uint16_t sub_group_count; + bool is_driver; + char * log_level; } neu_json_get_nodes_state_t; typedef struct { uint16_t n_node; neu_json_get_nodes_state_t *nodes; - char core_level[NEU_LOG_LEVEL_LEN]; + char * core_level; } neu_json_get_nodes_state_resp_t; int neu_json_encode_get_nodes_state_resp(void *json_object, void *param); diff --git a/src/parser/neu_json_tag.c b/src/parser/neu_json_tag.c index d38e36ce..b7e2b03d 100644 --- a/src/parser/neu_json_tag.c +++ b/src/parser/neu_json_tag.c @@ -470,7 +470,6 @@ int neu_json_decode_gtag_json(void *json_obj, neu_json_gtag_t *gtag_p) goto decode_exit; decode_fail: - free(gtag_p); free(gtag_elems[0].v.val_str); return -1; diff --git a/tests/ft/app/__init__.py b/tests/ft/app/__init__.py new file mode 100644 index 00000000..6da12771 --- /dev/null +++ b/tests/ft/app/__init__.py @@ -0,0 +1,3 @@ +import sys + +sys.path.append("tests/ft") diff --git a/tests/ft/app/test_app.py b/tests/ft/app/test_app.py new file mode 100644 index 00000000..65291ef8 --- /dev/null +++ b/tests/ft/app/test_app.py @@ -0,0 +1,97 @@ +import neuron.api as api +import neuron.error as error +import neuron.config as config +from neuron.common import * + +hold_int16 = [{"name": "hold_int16", "address": "1!400001", + "attribute": config.NEU_TAG_ATTRIBUTE_RW, "type": config.NEU_TYPE_INT16}] + +class TestDriver: + + @description(given="running neuron", when="add driver node", then="add success") + @pytest.mark.parametrize('node,plugin', [('modbus-tcp-1', config.PLUGIN_MODBUS_TCP)]) + def test_create_driver_node(self, node, plugin): + response = api.add_node(node=node, + plugin=plugin) + assert 200 == response.status_code + assert error.NEU_ERR_SUCCESS == response.json()['error'] + + @description(given="running neuron", when="add app node", then="add success") + @pytest.mark.parametrize('node,plugin', [('mqtt-1', config.PLUGIN_MQTT)]) + def test_create_app_node(self, node, plugin): + response = api.add_node(node=node, + plugin=plugin) + assert 200 == response.status_code + assert error.NEU_ERR_SUCCESS == response.json()['error'] + + @description(given="modbus tcp node", when="setting modbus tcp node and groups/tags", then="setting success") + def test_modbus_tcp_setting(self): + response = api.modbus_tcp_node_setting(node='modbus-tcp-1', port=502) + assert 200 == response.status_code + assert error.NEU_ERR_SUCCESS == response.json()['error'] + + response = api.add_group(node='modbus-tcp-1', group="group-1") + assert 200 == response.status_code + assert error.NEU_ERR_SUCCESS == response.json()['error'] + + response = api.add_group(node='modbus-tcp-1', group="group-2") + assert 200 == response.status_code + assert error.NEU_ERR_SUCCESS == response.json()['error'] + + response = api.add_group(node='modbus-tcp-1', group="group-3") + assert 200 == response.status_code + assert error.NEU_ERR_SUCCESS == response.json()['error'] + + response = api.add_tags(node='modbus-tcp-1', group="group-1", tags=hold_int16) + assert 200 == response.status_code + assert error.NEU_ERR_SUCCESS == response.json()['error'] + + response = api.add_tags(node='modbus-tcp-1', group="group-2", tags=hold_int16) + assert 200 == response.status_code + assert error.NEU_ERR_SUCCESS == response.json()['error'] + + response = api.add_tags(node='modbus-tcp-1', group="group-3", tags=hold_int16) + assert 200 == response.status_code + assert error.NEU_ERR_SUCCESS == response.json()['error'] + + @description(given="mqtt node", when="setting mqtt node and subscribe modbus group", then="setting&subscribe success") + def test_mqtt_setting(self): + response = api.mqtt_node_setting(node='mqtt-1') + assert 200 == response.status_code + assert error.NEU_ERR_SUCCESS == response.json()['error'] + + response = api.subscribe_groups(app='mqtt-1', groups=[{"driver": "modbus-tcp-1", "group": "group-1"}, + {"driver": "modbus-tcp-1", "group": "group-2"}, + {"driver": "modbus-tcp-1", "group": "group-3"}]) + assert 200 == response.status_code + assert error.NEU_ERR_SUCCESS == response.json()['error'] + + @description(given="mqtt node", when="subscribe/unsubscribe modbus group", then="return correct sub_group_count in node state") + def test_mqtt_sub_group_count(self): + response = api.get_nodes_state(node='mqtt-1') + assert 200 == response.status_code + assert 3 == response.json()['sub_group_count'] + + response = api.unsubscribe_group(app='mqtt-1', driver='modbus-tcp-1', group='group-1') + assert 200 == response.status_code + assert error.NEU_ERR_SUCCESS == response.json()['error'] + + response = api.unsubscribe_group(app='mqtt-1', driver='modbus-tcp-1', group='group-2') + assert 200 == response.status_code + assert error.NEU_ERR_SUCCESS == response.json()['error'] + + response = api.unsubscribe_group(app='mqtt-1', driver='modbus-tcp-1', group='group-3') + assert 200 == response.status_code + assert error.NEU_ERR_SUCCESS == response.json()['error'] + + response = api.get_nodes_state(node='mqtt-1') + assert 200 == response.status_code + assert 0 == response.json()['sub_group_count'] + + response = api.subscribe_group(app='mqtt-1', driver='modbus-tcp-1', group='group-1') + assert 200 == response.status_code + assert error.NEU_ERR_SUCCESS == response.json()['error'] + + response = api.get_nodes_state(node='mqtt-1') + assert 200 == response.status_code + assert 1 == response.json()['sub_group_count'] \ No newline at end of file diff --git a/tests/ft/neuron/api.py b/tests/ft/neuron/api.py index 72012c43..68ff10fc 100644 --- a/tests/ft/neuron/api.py +++ b/tests/ft/neuron/api.py @@ -157,7 +157,6 @@ def read_tag(node, group, tag, sync=False): finally: return x[0]['value'] - def read_tag_error(node, group, tag, sync=False): response = read_tags(node, group, sync) assert 200 == response.status_code @@ -282,6 +281,14 @@ def del_template_tags(tmpl, group, tags): def get_template_tags(tmpl, group, name): return requests.get(url=config.BASE_URL + "/api/v2/template/tag", headers={"Authorization": config.default_jwt}, params={"template": tmpl, "group": group, "name": name}) +def subscribe_group(app, driver, group): + return requests.post(url=config.BASE_URL + "/api/v2/subscribe", headers={"Authorization": config.default_jwt}, json={"app": app, "driver": driver, "group": group}) + +def subscribe_groups(app, groups): + return requests.post(url=config.BASE_URL + "/api/v2/subscribes", headers={"Authorization": config.default_jwt}, json={"app": app, "groups": groups}) + +def unsubscribe_group(app, driver, group): + return requests.delete(url=config.BASE_URL + "/api/v2/subscribe", headers={"Authorization": config.default_jwt}, json={"app": app, "driver": driver, "group": group}) def get_metrics(category="global", node=""): return requests.get(url=config.BASE_URL + "/api/v2/metrics?category=" + category + "&node=" + node, headers={"Authorization": config.default_jwt}) @@ -299,3 +306,8 @@ def modbus_rtu_node_setting(node, port, connection_mode=0, transport_mode=0, int "interval": interval, "host": host, "port": port, "timeout": timeout, "max_retries": max_retries, "link": link, "device": device, "stop": stop, "parity": parity, "baud": baud, "data": data}) + +def mqtt_node_setting(node): + return node_setting(node, json={"client-id": "neuron_aBcDeF", "qos":0, "format": 0, + "write-req-topic": f"/neuron/{node}/write/req", "write-resp-topic": f"/neuron/{node}/write/resp", + "offline-cache": False, "cache-sync-interval": 100, "host": "broker.emqx.io", "port": 1883, "username": "", "password": "", "ssl": False}) \ No newline at end of file diff --git a/tests/ft/neuron/config.py b/tests/ft/neuron/config.py index 863acfd5..b0bb8d06 100644 --- a/tests/ft/neuron/config.py +++ b/tests/ft/neuron/config.py @@ -68,3 +68,4 @@ NEU_DATA_8 = 3 PLUGIN_MODBUS_TCP = "Modbus TCP" PLUGIN_MODBUS_RTU = "Modbus RTU" +PLUGIN_MQTT = "MQTT"