static int rpc_handler(sr_session_ctx_t *session) { sr_subscription_ctx_t *subscription = NULL; int rc = SR_ERR_OK; /* subscribe for handling RPC */ rc = sr_rpc_subscribe_tree(session, "/turing-machine:run-until", rpc_cb, (void *)session, SR_SUBSCR_DEFAULT, &subscription); if (SR_ERR_OK != rc) { fprintf(stderr, "Error by sr_rpc_subscribe: %s\n", sr_strerror(rc)); goto cleanup; } printf("\n\n ========== SUBSCRIBED FOR HANDLING RPC ==========\n\n"); /* loop until ctrl-c is pressed / SIGINT is received */ signal(SIGINT, sigint_handler); signal(SIGPIPE, SIG_IGN); while (!exit_application) { sleep(1000); /* or do some more useful work... */ } printf("Application exit requested, exiting.\n"); cleanup: if (NULL != subscription) { sr_unsubscribe(session, subscription); } return rc; }
static int event_notif_subscriber(sr_session_ctx_t *session) { sr_subscription_ctx_t *subscription = NULL; int rc = SR_ERR_OK; /* subscribe for the notification */ rc = sr_event_notif_subscribe(session, "/turing-machine:paused", event_notif_cb, NULL, SR_SUBSCR_DEFAULT, &subscription); if (SR_ERR_OK != rc) { fprintf(stderr, "Error by sr_event_notif_subscribe: %s\n", sr_strerror(rc)); goto cleanup; } printf("\n\n ========== SUBSCRIBED FOR EVENT NOTIFICATION ==========\n\n"); /* loop until ctrl-c is pressed / SIGINT is received */ signal(SIGINT, sigint_handler); signal(SIGPIPE, SIG_IGN); while (!exit_application) { sleep(1000); /* or do some more useful work... */ } printf("Application exit requested, exiting.\n"); cleanup: if (NULL != subscription) { sr_unsubscribe(session, subscription); } return rc; }
void Subscribe::unsubscribe() { int ret = sr_unsubscribe(_sess->_sess, _sub); if (SR_ERR_OK != ret) { throw_exception(ret); } _sub = nullptr; }
Subscribe::~Subscribe() { if (_sub && _sess) { int ret = sr_unsubscribe(_sess->_sess, _sub); if (ret != SR_ERR_OK) { //this exception can't be catched //throw_exception(ret); } _sub = nullptr; } for(unsigned int i=0; i < wrap_cb_l.size(); i++){ additional_cleanup(wrap_cb_l[i]); } }
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){ sigset_t mask, oldmask; /* Set up the mask of signals to temporarily block. */ sigemptyset (&mask); sigaddset (&mask, SIGUSR1); sigprocmask (SIG_BLOCK, &mask, &oldmask); printf("Pid: %d\n", getpid()); signal(SIGUSR1, sig_handler); sr_conn_ctx_t *connection = NULL; sr_session_ctx_t *session = NULL; sr_subscription_ctx_t *subscription = NULL; int rc = SR_ERR_OK; sr_log_stderr(SR_LL_DBG); /* connect to sysrepo */ rc = sr_connect("example_application", SR_CONN_DEFAULT, &connection); if (SR_ERR_OK != rc) { goto cleanup; } /* start session */ rc = sr_session_start(connection, SR_DS_STARTUP, SR_SESS_DEFAULT, &session); if (SR_ERR_OK != rc) { goto cleanup; } /* read startup config */ printf("\n\n ========== READING STARTUP CONFIG: ==========\n\n"); /* subscribe for changes in running config */ rc = sr_module_change_subscribe(session, "ietf-interfaces", module_change_cb, NULL, 0, SR_SUBSCR_DEFAULT, &subscription); if (SR_ERR_OK != rc) { goto cleanup; } printf("\n\n ========== STARTUP CONFIG APPLIED AS RUNNING ==========\n\n"); /* Wait for a signal to arrive. */ while (!usr_interrupt) { sigsuspend (&oldmask); } sigprocmask (SIG_UNBLOCK, &mask, NULL); printf("Signal received\n"); cleanup: if (NULL != subscription) { sr_unsubscribe(session, subscription); } if (NULL != session) { sr_session_stop(session); } if (NULL != connection) { sr_disconnect(connection); } return rc; }
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(); }
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; }