void Session::commit() { int ret = sr_commit(_sess); if (ret != SR_ERR_OK) { throw_exception(ret); } }
static void cl_notif_priority_test(void **state) { sr_conn_ctx_t *conn = *state; assert_non_null(conn); sr_session_ctx_t *session = NULL; sr_subscription_ctx_t *subscription = NULL; priority_t priority = {0}; int rc = SR_ERR_OK; /* start session */ rc = sr_session_start(conn, SR_DS_RUNNING, SR_SESS_DEFAULT, &session); assert_int_equal(rc, SR_ERR_OK); rc = sr_module_change_subscribe(session, "test-module", priority_zero_cb, &priority, 0, SR_SUBSCR_DEFAULT, &subscription); assert_int_equal(rc, SR_ERR_OK); rc = sr_module_change_subscribe(session, "test-module", priority_two_cb, &priority, 2, SR_SUBSCR_DEFAULT | SR_SUBSCR_CTX_REUSE, &subscription); assert_int_equal(rc, SR_ERR_OK); rc = sr_module_change_subscribe(session, "test-module", priority_one_cb, &priority, 1, SR_SUBSCR_DEFAULT | SR_SUBSCR_CTX_REUSE, &subscription); assert_int_equal(rc, SR_ERR_OK); rc = sr_set_item(session, "/test-module:user[name='userA']", NULL, SR_EDIT_DEFAULT); assert_int_equal(rc, SR_ERR_OK); rc = sr_commit(session); assert_int_equal(rc, SR_ERR_OK); /* timeout 10 sec */ for (size_t i = 0; i < 1000; i++) { if (priority.count >= 3) break; usleep(10000); /* 10 ms */ } assert_int_equal(priority.count, 3); assert_int_equal(2, priority.cb [0]); assert_int_equal(1, priority.cb [1]); assert_int_equal(0, priority.cb [2]); /* check that cb were called in correct order according to the priority */ sr_unsubscribe(session, subscription); sr_session_stop(session); }
int main(int argc, char **argv) { int rc = SR_ERR_OK; sr_conn_ctx_t *conn = NULL; sr_session_ctx_t *sess = NULL; sr_val_t val = {0}; sr_log_stderr(SR_LL_DBG); rc = sr_connect("push kea config", SR_CONN_DEFAULT, &conn); CHECK_RC(rc, cleanup); rc = sr_session_start(conn, SR_DS_STARTUP, SR_SESS_DEFAULT, &sess); CHECK_RC(rc, cleanup); /* socket type */ val.xpath = "/ietf-kea-dhcpv6:server/serv-attributes/control-socket/socket-type"; val.type = SR_STRING_T; val.data.string_val = "unix"; rc = sr_set_item(sess, val.xpath, &val, SR_EDIT_DEFAULT); CHECK_RC(rc, cleanup); /* socket name */ val.xpath = "/ietf-kea-dhcpv6:server/serv-attributes/control-socket/socket-name"; val.type = SR_STRING_T; val.data.string_val = "/tmp/kea-dhcp6-ctrl.sock"; rc = sr_set_item(sess, val.xpath, &val, SR_EDIT_DEFAULT); CHECK_RC(rc, cleanup); rc = sr_commit(sess); /* retrieve field */ sr_val_t* val2 = 0; rc = sr_get_item(sess, val.xpath, &val2); printf("Retrieved: [%s]\n", val.data.string_val); sr_free_val(val2); CHECK_RC(rc, cleanup); cleanup: sr_session_stop(sess); sr_disconnect(conn); }
static void cl_fd_poll_test(void **state) { sr_conn_ctx_t *conn = *state; assert_non_null(conn); sr_session_ctx_t *session = NULL; sr_subscription_ctx_t *subscription = NULL; sr_fd_change_t *fd_change_set = NULL; size_t fd_change_set_cnt = 0; int init_fd = 0; int ret = 0, rc = SR_ERR_OK; bool callback_called = false; /* init app-local watcher */ rc = sr_fd_watcher_init(&init_fd); assert_int_equal(rc, SR_ERR_OK); poll_fd_set[0].fd = init_fd; poll_fd_set[0].events = POLLIN; poll_fd_cnt = 1; /* start session */ rc = sr_session_start(conn, SR_DS_CANDIDATE, SR_SESS_DEFAULT, &session); assert_int_equal(rc, SR_ERR_OK); /* subscribe for changes */ rc = sr_module_change_subscribe(session, "example-module", module_change_cb, &callback_called, 0, SR_SUBSCR_DEFAULT | SR_SUBSCR_APPLY_ONLY, &subscription); assert_int_equal(rc, SR_ERR_OK); /* create the list instance */ rc = sr_set_item(session, "/example-module:container/list[key1='123'][key2='456']", NULL, SR_EDIT_DEFAULT); assert_int_equal(rc, SR_ERR_OK); /* commit changes */ rc = sr_commit(session); assert_int_equal(rc, SR_ERR_OK); do { ret = poll(poll_fd_set, poll_fd_cnt, -1); assert_int_not_equal(ret, -1); for (size_t i = 0; i < poll_fd_cnt; i++) { assert_false((poll_fd_set[i].revents & POLLERR) || (poll_fd_set[i].revents & POLLHUP) || (poll_fd_set[i].revents & POLLNVAL)); if (poll_fd_set[i].revents & POLLIN) { rc = sr_fd_event_process(poll_fd_set[i].fd, SR_FD_INPUT_READY, &fd_change_set, &fd_change_set_cnt); assert_int_equal(rc, SR_ERR_OK); cl_fd_change_set_process(fd_change_set, fd_change_set_cnt); free(fd_change_set); fd_change_set = NULL; fd_change_set_cnt = 0; } if (poll_fd_set[i].revents & POLLOUT) { rc = sr_fd_event_process(poll_fd_set[i].fd, SR_FD_OUTPUT_READY, &fd_change_set, &fd_change_set_cnt); assert_int_equal(rc, SR_ERR_OK); cl_fd_change_set_process(fd_change_set, fd_change_set_cnt); free(fd_change_set); fd_change_set = NULL; fd_change_set_cnt = 0; } } } while ((SR_ERR_OK == rc) && !callback_called); /* unsubscribe after callback has been called */ rc = sr_unsubscribe(session, subscription); assert_int_equal(rc, SR_ERR_OK); callback_called = false; /* stop the session */ rc = sr_session_stop(session); assert_int_equal(rc, SR_ERR_OK); /* cleanup app-local watcher */ sr_fd_watcher_cleanup(); }
/** * @brief Import content of the specified datastore for the given module from a file * referenced by the descriptor 'fd_in' */ static int srcfg_import_datastore(struct ly_ctx *ly_ctx, int fd_in, const char *module_name, srcfg_datastore_t datastore, LYD_FORMAT format, bool permanent) { int rc = SR_ERR_INTERNAL; unsigned i = 0; struct lyd_node *new_data_tree = NULL; struct lyd_node *current_data_tree = NULL; struct lyd_difflist *diff = NULL; char *first_xpath = NULL, *second_xpath = NULL; char *input_data = NULL; int ret = 0; struct stat info; CHECK_NULL_ARG2(ly_ctx, module_name); /* parse input data */ ret = fstat(fd_in, &info); CHECK_NOT_MINUS1_LOG_GOTO(ret, rc, SR_ERR_INTERNAL, cleanup, "Unable to obtain input file info: %s.", sr_strerror_safe(errno)); ly_errno = LY_SUCCESS; if (S_ISREG(info.st_mode)) { /* load (using mmap) and parse the input data in one step */ new_data_tree = lyd_parse_fd(ly_ctx, fd_in, format, LYD_OPT_STRICT | LYD_OPT_CONFIG); } else { /* most likely STDIN */ /* load input data into the memory first */ ret = srcfg_read_file_content(fd_in, &input_data); CHECK_RC_MSG_GOTO(ret, cleanup, "Unable to read the input data."); /* parse the input data stored inside memory buffer */ new_data_tree = lyd_parse_mem(ly_ctx, input_data, format, LYD_OPT_STRICT | LYD_OPT_CONFIG); } if (NULL == new_data_tree && LY_SUCCESS != ly_errno) { SR_LOG_ERR("Unable to parse the input data: %s", ly_errmsg()); goto cleanup; } /* validate input data */ if (NULL != new_data_tree) { ret = lyd_validate(&new_data_tree, LYD_OPT_STRICT | LYD_OPT_CONFIG | LYD_WD_IMPL_TAG); CHECK_ZERO_LOG_GOTO(ret, rc, SR_ERR_INTERNAL, cleanup, "Input data are not valid: %s", ly_errmsg()); } /* remove default nodes */ lyd_wd_cleanup(&new_data_tree, 0); /* get data tree of currently stored configuration */ rc = srcfg_get_module_data(ly_ctx, module_name, ¤t_data_tree); if (SR_ERR_OK != rc) { goto cleanup; } /* get the list of changes made by the user */ diff = lyd_diff(current_data_tree, new_data_tree, 0); if (NULL == diff) { SR_LOG_ERR("Unable to get the list of changes: %s", ly_errmsg()); goto cleanup; } /* iterate over the list of differences and for each issue corresponding Sysrepo command(s) */ while (diff->type && LYD_DIFF_END != diff->type[i]) { if (NULL != diff->first[i]) { first_xpath = lyd_path(diff->first[i]); if (NULL == first_xpath) { SR_LOG_ERR("Error returned from lyd_path: %s.", ly_errmsg()); goto cleanup; } } if (NULL != diff->second[i]) { second_xpath = lyd_path(diff->second[i]); if (NULL == second_xpath) { free(first_xpath); first_xpath = NULL; SR_LOG_ERR("Error returned from lyd_path: %s.", ly_errmsg()); goto cleanup; } } switch (diff->type[i]) { case LYD_DIFF_DELETED: SR_LOG_DBG("<LYD_DIFF_DELETED> node: %s", first_xpath); rc = srcfg_convert_lydiff_deleted(first_xpath); break; case LYD_DIFF_CHANGED: SR_LOG_DBG("<LYD_DIFF_CHANGED> orig: %s, new: %s", first_xpath, second_xpath); rc = srcfg_convert_lydiff_changed(first_xpath, diff->second[i]); break; case LYD_DIFF_MOVEDAFTER1: SR_LOG_DBG("<LYD_DIFF_MOVEDAFTER1> moved: %s, after: %s", first_xpath, second_xpath); rc = srcfg_convert_lydiff_movedafter(first_xpath, second_xpath); break; case LYD_DIFF_CREATED: SR_LOG_DBG("<LYD_DIFF_CREATED> parent: %s, new node: %s", first_xpath, second_xpath); rc = srcfg_convert_lydiff_created(diff->second[i]); break; case LYD_DIFF_MOVEDAFTER2: SR_LOG_DBG("<LYD_DIFF_MOVEDAFTER2> after: %s, this new node was inserted: %s", first_xpath, second_xpath); rc = srcfg_convert_lydiff_movedafter(second_xpath, first_xpath); break; default: assert(0 && "not reachable"); } free(first_xpath); free(second_xpath); first_xpath = second_xpath = NULL; if (SR_ERR_OK != rc) { goto cleanup; } ++i; } if (0 == i) { SR_LOG_DBG_MSG("No changes were made."); } else { /* commit the changes */ rc = sr_commit(srcfg_session); if (SR_ERR_OK != rc) { SR_LOG_ERR("Error returned from sr_commit: %s.", sr_strerror(rc)); goto cleanup; } if (SRCFG_STORE_RUNNING == datastore && permanent) { /* copy running datastore data into the startup datastore */ rc = sr_copy_config(srcfg_session, module_name, SR_DS_RUNNING, SR_DS_STARTUP); if (SR_ERR_OK != rc) { SR_LOG_ERR("Error returned from sr_copy_config: %s.", sr_strerror(rc)); goto cleanup; } } } rc = SR_ERR_OK; cleanup: if (NULL != diff) { lyd_free_diff(diff); } if (NULL != current_data_tree) { lyd_free_withsiblings(current_data_tree); } if (NULL != new_data_tree) { lyd_free_withsiblings(new_data_tree); } if (input_data) { free(input_data); } return rc; }
static void cl_children_subscription_test(void **state) { sr_conn_ctx_t *conn = *state; assert_non_null(conn); sr_session_ctx_t *session = NULL; sr_subscription_ctx_t *subscription = NULL; changes_t changes = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cv = PTHREAD_COND_INITIALIZER, 0}; struct timespec ts; int rc = SR_ERR_OK; /* start session */ rc = sr_session_start(conn, SR_DS_RUNNING, SR_SESS_DEFAULT, &session); assert_int_equal(rc, SR_ERR_OK); rc = sr_subtree_change_subscribe(session, "/example-module:container/list/leaf", subtree_example_change_cb, &changes, 0, SR_SUBSCR_DEFAULT, &subscription); assert_int_equal(rc, SR_ERR_OK); /* delete the parent of the subscribed node */ rc = sr_delete_item(session, "/example-module:*", SR_EDIT_DEFAULT); assert_int_equal(rc, SR_ERR_OK); pthread_mutex_lock(&changes.mutex); rc = sr_commit(session); assert_int_equal(rc, SR_ERR_OK); sr_clock_get_time(CLOCK_REALTIME, &ts); ts.tv_sec += COND_WAIT_SEC; pthread_cond_timedwait(&changes.cv, &changes.mutex, &ts); assert_int_equal(changes.cnt, 5); for (int i= 0; i < changes.cnt; i++) { assert_int_equal(changes.oper[i], SR_OP_DELETED); } assert_string_equal("/example-module:container", changes.old_values[0]->xpath); assert_string_equal("/example-module:container/list[key1='key1'][key2='key2']", changes.old_values[1]->xpath); assert_string_equal("/example-module:container/list[key1='key1'][key2='key2']/key1", changes.old_values[2]->xpath); assert_string_equal("/example-module:container/list[key1='key1'][key2='key2']/key2", changes.old_values[3]->xpath); assert_string_equal("/example-module:container/list[key1='key1'][key2='key2']/leaf", changes.old_values[4]->xpath); for (size_t i = 0; i < changes.cnt; i++) { sr_free_val(changes.new_values[i]); sr_free_val(changes.old_values[i]); } pthread_mutex_unlock(&changes.mutex); /* check that cb were called in correct order according to the priority */ sr_unsubscribe(session, subscription); sr_session_stop(session); } int main() { const struct CMUnitTest tests[] = { cmocka_unit_test_setup_teardown(cl_get_changes_create_test, sysrepo_setup, sysrepo_teardown), cmocka_unit_test_setup_teardown(cl_get_changes_modified_test, sysrepo_setup, sysrepo_teardown), cmocka_unit_test_setup_teardown(cl_get_changes_deleted_test, sysrepo_setup, sysrepo_teardown), cmocka_unit_test_setup_teardown(cl_get_changes_moved_test, sysrepo_setup, sysrepo_teardown), cmocka_unit_test_setup_teardown(cl_notif_priority_test, sysrepo_setup, sysrepo_teardown), cmocka_unit_test_setup_teardown(cl_whole_module_changes, sysrepo_setup, sysrepo_teardown), cmocka_unit_test_setup_teardown(cl_invalid_xpath_test, sysrepo_setup, sysrepo_teardown), cmocka_unit_test_setup_teardown(cl_children_subscription_test, sysrepo_setup, sysrepo_teardown), }; return cmocka_run_group_tests(tests, NULL, NULL); }
static void cl_invalid_xpath_test(void **state) { sr_conn_ctx_t *conn = *state; assert_non_null(conn); sr_session_ctx_t *session = NULL; sr_subscription_ctx_t *subscription = NULL; changes_t changes = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cv = PTHREAD_COND_INITIALIZER, 0}; struct timespec ts; int rc = SR_ERR_OK; /* start session */ rc = sr_session_start(conn, SR_DS_RUNNING, SR_SESS_DEFAULT, &session); assert_int_equal(rc, SR_ERR_OK); rc = sr_module_change_subscribe(session, "test-module", cl_invalid_change_xpath_cb, &changes, 0, SR_SUBSCR_DEFAULT, &subscription); assert_int_equal(rc, SR_ERR_OK); sr_val_t v = {0}; v.type = SR_UINT8_T; v.data.uint8_val = 19; rc = sr_set_item(session, "/test-module:main/ui8", &v, SR_EDIT_DEFAULT); assert_int_equal(rc, SR_ERR_OK); pthread_mutex_lock(&changes.mutex); rc = sr_commit(session); assert_int_equal(rc, SR_ERR_OK); sr_clock_get_time(CLOCK_REALTIME, &ts); ts.tv_sec += COND_WAIT_SEC; pthread_cond_timedwait(&changes.cv, &changes.mutex, &ts); pthread_mutex_unlock(&changes.mutex); /* check that cb were called in correct order according to the priority */ sr_unsubscribe(session, subscription); sr_session_stop(session); } int subtree_example_change_cb(sr_session_ctx_t *session, const char *xpath, sr_notif_event_t event, void *private_ctx) { changes_t *ch = (changes_t *) private_ctx; sr_change_iter_t *it = NULL; int rc = SR_ERR_OK; pthread_mutex_lock(&ch->mutex); rc = sr_get_changes_iter(session, "/example-module:*" , &it); puts("Iteration over changes started"); if (SR_ERR_OK != rc) { puts("sr get changes iter failed"); goto cleanup; } ch->cnt = 0; while (ch->cnt < MAX_CHANGE) { rc = sr_get_change_next(session, it, &ch->oper[ch->cnt], &ch->old_values[ch->cnt], &ch->new_values[ch->cnt]); if (SR_ERR_OK != rc) { break; } ch->cnt++; } cleanup: sr_free_change_iter(it); pthread_cond_signal(&ch->cv); pthread_mutex_unlock(&ch->mutex); return SR_ERR_OK; }
static void cl_whole_module_changes(void **state) { sr_conn_ctx_t *conn = *state; assert_non_null(conn); sr_session_ctx_t *session = NULL; sr_subscription_ctx_t *subscription = NULL; changes_t changes = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cv = PTHREAD_COND_INITIALIZER, 0}; struct timespec ts; int rc = SR_ERR_OK; /* start session */ rc = sr_session_start(conn, SR_DS_RUNNING, SR_SESS_DEFAULT, &session); assert_int_equal(rc, SR_ERR_OK); rc = sr_module_change_subscribe(session, "test-module", cl_whole_module_cb, &changes, 0, SR_SUBSCR_DEFAULT, &subscription); assert_int_equal(rc, SR_ERR_OK); sr_val_t v = {0}; v.type = SR_UINT8_T; v.data.uint8_val = 19; rc = sr_set_item(session, "/test-module:main/ui8", &v, SR_EDIT_DEFAULT); assert_int_equal(rc, SR_ERR_OK); rc = sr_set_item(session, "/test-module:user[name='userA']", NULL, SR_EDIT_DEFAULT); assert_int_equal(rc, SR_ERR_OK); pthread_mutex_lock(&changes.mutex); rc = sr_commit(session); assert_int_equal(rc, SR_ERR_OK); sr_clock_get_time(CLOCK_REALTIME, &ts); ts.tv_sec += COND_WAIT_SEC; pthread_cond_timedwait(&changes.cv, &changes.mutex, &ts); for (int i= 0; i < changes.cnt; i++) { if (NULL != changes.new_values[i]) { puts(changes.new_values[i]->xpath); } } assert_int_equal(changes.cnt, 4); assert_int_equal(changes.oper[0], SR_OP_MODIFIED); assert_non_null(changes.new_values[0]); assert_non_null(changes.old_values[0]); assert_string_equal("/test-module:main/ui8", changes.new_values[0]->xpath); assert_int_equal(changes.oper[1], SR_OP_CREATED); assert_non_null(changes.new_values[1]); assert_null(changes.old_values[1]); assert_string_equal("/test-module:user[name='userA']", changes.new_values[1]->xpath); assert_int_equal(changes.oper[2], SR_OP_CREATED); assert_non_null(changes.new_values[2]); assert_null(changes.old_values[2]); assert_string_equal("/test-module:user[name='userA']/name", changes.new_values[2]->xpath); assert_int_equal(changes.oper[3], SR_OP_MOVED); assert_non_null(changes.new_values[3]); assert_null(changes.old_values[3]); assert_string_equal("/test-module:user[name='userA']", changes.new_values[3]->xpath); for (size_t i = 0; i < changes.cnt; i++) { sr_free_val(changes.new_values[i]); sr_free_val(changes.old_values[i]); } pthread_mutex_unlock(&changes.mutex); /* check that cb were called in correct order according to the priority */ sr_unsubscribe(session, subscription); sr_session_stop(session); } int cl_invalid_change_xpath_cb(sr_session_ctx_t *session, const char *module_name, sr_notif_event_t ev, void *private_ctx) { changes_t *ch = (changes_t *) private_ctx; sr_change_iter_t *it = NULL; int rc = SR_ERR_OK; pthread_mutex_lock(&ch->mutex); char change_path[50] = {0,}; snprintf(change_path, 50, "/---ERR%s:*", module_name); rc = sr_get_changes_iter(session, change_path, &it); assert_int_not_equal(SR_ERR_OK, rc); snprintf(change_path, 50, "/%s:abcdefgh", module_name); rc = sr_get_changes_iter(session, change_path, &it); assert_int_not_equal(SR_ERR_OK, rc); pthread_cond_signal(&ch->cv); pthread_mutex_unlock(&ch->mutex); return SR_ERR_OK; }
static void cl_get_changes_create_test(void **state) { sr_conn_ctx_t *conn = *state; assert_non_null(conn); sr_session_ctx_t *session = NULL; sr_subscription_ctx_t *subscription = NULL; changes_t changes = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cv = PTHREAD_COND_INITIALIZER, 0}; struct timespec ts; sr_val_t *val = NULL; const char *xpath = NULL; int rc = SR_ERR_OK; xpath = "/example-module:container/list[key1='abc'][key2='def']"; /* start session */ rc = sr_session_start(conn, SR_DS_CANDIDATE, SR_SESS_DEFAULT, &session); assert_int_equal(rc, SR_ERR_OK); rc = sr_module_change_subscribe(session, "example-module", list_changes_cb, &changes, 0, SR_SUBSCR_DEFAULT, &subscription); assert_int_equal(rc, SR_ERR_OK); /* check the list presence in candidate */ rc = sr_get_item(session, xpath, &val); assert_int_equal(rc, SR_ERR_NOT_FOUND); /* create the list instance */ rc = sr_set_item(session, xpath, NULL, SR_EDIT_DEFAULT); assert_int_equal(rc, SR_ERR_OK); /* save changes to running */ pthread_mutex_lock(&changes.mutex); rc = sr_commit(session); assert_int_equal(rc, SR_ERR_OK); sr_clock_get_time(CLOCK_REALTIME, &ts); ts.tv_sec += COND_WAIT_SEC; pthread_cond_timedwait(&changes.cv, &changes.mutex, &ts); assert_int_equal(changes.cnt, 3); assert_int_equal(changes.oper[0], SR_OP_CREATED); assert_non_null(changes.new_values[0]); assert_null(changes.old_values[0]); assert_string_equal(xpath, changes.new_values[0]->xpath); assert_int_equal(changes.oper[1], SR_OP_CREATED); assert_non_null(changes.new_values[1]); assert_null(changes.old_values[1]); assert_string_equal("/example-module:container/list[key1='abc'][key2='def']/key1", changes.new_values[1]->xpath); assert_int_equal(changes.oper[2], SR_OP_CREATED); assert_non_null(changes.new_values[2]); assert_null(changes.old_values[2]); assert_string_equal("/example-module:container/list[key1='abc'][key2='def']/key2", changes.new_values[2]->xpath); for (size_t i = 0; i < changes.cnt; i++) { sr_free_val(changes.new_values[i]); sr_free_val(changes.old_values[i]); } pthread_mutex_unlock(&changes.mutex); rc = sr_unsubscribe(NULL, subscription); assert_int_equal(rc, SR_ERR_OK); rc = sr_session_stop(session); assert_int_equal(rc, SR_ERR_OK); } static void cl_get_changes_modified_test(void **state) { sr_conn_ctx_t *conn = *state; assert_non_null(conn); sr_session_ctx_t *session = NULL; sr_subscription_ctx_t *subscription = NULL; changes_t changes = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cv = PTHREAD_COND_INITIALIZER, 0}; struct timespec ts; sr_val_t *val = NULL; const char *xpath = NULL; int rc = SR_ERR_OK; xpath = "/example-module:container/list[key1='key1'][key2='key2']/leaf"; /* start session */ rc = sr_session_start(conn, SR_DS_CANDIDATE, SR_SESS_DEFAULT, &session); assert_int_equal(rc, SR_ERR_OK); rc = sr_module_change_subscribe(session, "example-module", list_changes_cb, &changes, 0, SR_SUBSCR_DEFAULT, &subscription); assert_int_equal(rc, SR_ERR_OK); /* check the list presence in candidate */ rc = sr_get_item(session, xpath, &val); assert_int_equal(rc, SR_ERR_OK); sr_val_t new_val = {0}; new_val.type = SR_STRING_T; new_val.data.string_val = "abcdef"; /* create the list instance */ rc = sr_set_item(session, xpath, &new_val, SR_EDIT_DEFAULT); assert_int_equal(rc, SR_ERR_OK); /* save changes to running */ pthread_mutex_lock(&changes.mutex); rc = sr_commit(session); assert_int_equal(rc, SR_ERR_OK); sr_clock_get_time(CLOCK_REALTIME, &ts); ts.tv_sec += COND_WAIT_SEC; pthread_cond_timedwait(&changes.cv, &changes.mutex, &ts); assert_int_equal(changes.cnt, 1); assert_int_equal(changes.oper[0], SR_OP_MODIFIED); assert_non_null(changes.new_values[0]); assert_non_null(changes.old_values[0]); assert_string_equal(val->data.string_val, changes.old_values[0]->data.string_val); assert_string_equal(new_val.data.string_val, changes.new_values[0]->data.string_val); for (size_t i = 0; i < changes.cnt; i++) { sr_free_val(changes.new_values[i]); sr_free_val(changes.old_values[i]); } sr_free_val(val); pthread_mutex_unlock(&changes.mutex); rc = sr_unsubscribe(NULL, subscription); assert_int_equal(rc, SR_ERR_OK); rc = sr_session_stop(session); assert_int_equal(rc, SR_ERR_OK); } static void cl_get_changes_deleted_test(void **state) { sr_conn_ctx_t *conn = *state; assert_non_null(conn); sr_session_ctx_t *session = NULL; sr_subscription_ctx_t *subscription = NULL; changes_t changes = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cv = PTHREAD_COND_INITIALIZER, 0}; struct timespec ts; sr_val_t *val = NULL; const char *xpath = NULL; int rc = SR_ERR_OK; xpath = "/example-module:container"; /* start session */ rc = sr_session_start(conn, SR_DS_CANDIDATE, SR_SESS_DEFAULT, &session); assert_int_equal(rc, SR_ERR_OK); rc = sr_module_change_subscribe(session, "example-module", list_changes_cb, &changes, 0, SR_SUBSCR_DEFAULT, &subscription); assert_int_equal(rc, SR_ERR_OK); /* check the list presence in candidate */ rc = sr_get_item(session, xpath, &val); assert_int_equal(rc, SR_ERR_OK); sr_free_val(val); /* delete container */ rc = sr_delete_item(session, xpath, SR_EDIT_DEFAULT); assert_int_equal(rc, SR_ERR_OK); /* save changes to running */ pthread_mutex_lock(&changes.mutex); rc = sr_commit(session); assert_int_equal(rc, SR_ERR_OK); sr_clock_get_time(CLOCK_REALTIME, &ts); ts.tv_sec += COND_WAIT_SEC; pthread_cond_timedwait(&changes.cv, &changes.mutex, &ts); assert_int_equal(changes.cnt, 5); assert_int_equal(changes.oper[0], SR_OP_DELETED); assert_null(changes.new_values[0]); assert_non_null(changes.old_values[0]); assert_string_equal(xpath, changes.old_values[0]->xpath); assert_int_equal(changes.oper[1], SR_OP_DELETED); assert_null(changes.new_values[1]); assert_non_null(changes.old_values[1]); assert_string_equal("/example-module:container/list[key1='key1'][key2='key2']", changes.old_values[1]->xpath); assert_int_equal(changes.oper[2], SR_OP_DELETED); assert_null(changes.new_values[2]); assert_non_null(changes.old_values[2]); assert_string_equal("/example-module:container/list[key1='key1'][key2='key2']/key1", changes.old_values[2]->xpath); assert_int_equal(changes.oper[3], SR_OP_DELETED); assert_null(changes.new_values[3]); assert_non_null(changes.old_values[3]); assert_string_equal("/example-module:container/list[key1='key1'][key2='key2']/key2", changes.old_values[3]->xpath); assert_int_equal(changes.oper[4], SR_OP_DELETED); assert_null(changes.new_values[4]); assert_non_null(changes.old_values[4]); assert_string_equal("/example-module:container/list[key1='key1'][key2='key2']/leaf", changes.old_values[4]->xpath); for (size_t i = 0; i < changes.cnt; i++) { sr_free_val(changes.new_values[i]); sr_free_val(changes.old_values[i]); } pthread_mutex_unlock(&changes.mutex); rc = sr_unsubscribe(NULL, subscription); assert_int_equal(rc, SR_ERR_OK); rc = sr_session_stop(session); assert_int_equal(rc, SR_ERR_OK); } static void cl_get_changes_moved_test(void **state) { sr_conn_ctx_t *conn = *state; assert_non_null(conn); sr_session_ctx_t *session = NULL; sr_subscription_ctx_t *subscription = NULL; changes_t changes = {.mutex = PTHREAD_MUTEX_INITIALIZER, .cv = PTHREAD_COND_INITIALIZER, 0}; struct timespec ts; const char *xpath = NULL; int rc = SR_ERR_OK; xpath = "/test-module:ordered-numbers"; /* start session */ rc = sr_session_start(conn, SR_DS_STARTUP, SR_SESS_DEFAULT, &session); assert_int_equal(rc, SR_ERR_OK); sr_val_t v = {0}; v.type = SR_UINT8_T; v.data.uint8_val = 1; /* create user ordered leaf-list instance */ rc = sr_set_item(session, xpath, &v, SR_EDIT_STRICT); assert_int_equal(rc, SR_ERR_OK); v.data.uint8_val = 2; rc = sr_set_item(session, xpath, &v, SR_EDIT_STRICT); assert_int_equal(rc, SR_ERR_OK); v.data.uint8_val = 3; rc = sr_set_item(session, xpath, &v, SR_EDIT_STRICT); assert_int_equal(rc, SR_ERR_OK); /* save changes to running */ rc = sr_commit(session); assert_int_equal(rc, SR_ERR_OK); rc = sr_session_switch_ds(session, SR_DS_CANDIDATE); assert_int_equal(rc, SR_ERR_OK); rc = sr_module_change_subscribe(session, "test-module", list_changes_cb, &changes, 0, SR_SUBSCR_DEFAULT, &subscription); assert_int_equal(rc, SR_ERR_OK); /* move leaf-list */ rc = sr_move_item(session, "/test-module:ordered-numbers[.='3']", SR_MOVE_AFTER, "/test-module:ordered-numbers[.='1']"); assert_int_equal(rc, SR_ERR_OK); /* save changes to running */ pthread_mutex_lock(&changes.mutex); rc = sr_commit(session); assert_int_equal(rc, SR_ERR_OK); sr_clock_get_time(CLOCK_REALTIME, &ts); ts.tv_sec += COND_WAIT_SEC; pthread_cond_timedwait(&changes.cv, &changes.mutex, &ts); assert_int_equal(changes.cnt, 1); assert_int_equal(changes.oper[0], SR_OP_MOVED); assert_non_null(changes.new_values[0]); assert_non_null(changes.old_values[0]); assert_string_equal(xpath, changes.old_values[0]->xpath); assert_int_equal(changes.new_values[0]->data.uint8_val, 2); assert_int_equal(changes.old_values[0]->data.uint8_val, 3); for (size_t i = 0; i < changes.cnt; i++) { sr_free_val(changes.new_values[i]); sr_free_val(changes.old_values[i]); } pthread_mutex_unlock(&changes.mutex); rc = sr_unsubscribe(NULL, subscription); assert_int_equal(rc, SR_ERR_OK); rc = sr_session_stop(session); assert_int_equal(rc, SR_ERR_OK); } typedef struct priority_s { int count; int cb[3]; }priority_t; static int priority_zero_cb(sr_session_ctx_t *session, const char *module_name, sr_notif_event_t ev, void *private_ctx) { priority_t *pr = (priority_t *) private_ctx; pr->cb[pr->count] = 0; pr->count++; return SR_ERR_OK; }