Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 57 additions & 27 deletions src/tree_data.c
Original file line number Diff line number Diff line change
Expand Up @@ -3825,17 +3825,65 @@ lyd_link_leafref_node(const struct lyd_node_term *node, const struct lyd_node_te
return LY_SUCCESS;
}

/**
* @brief Traverse through data tree node suitable types and adds leafrefs links to the given nodes
*
* This API requires usage of ::LY_CTX_LEAFREF_LINKING context flag.
*
* @param[in] tree The data tree root node.
* @param[in] cur_node The current data node.
* @param[in] value The current node value.
* @param[in] type The leaf/leaf-list type of given data node.
*
* @return LY_SUCCESS on success.
* @return LY_ERR value on error.
*/
static LY_ERR
lyd_leafref_link_node_tree_type(const struct lyd_node *tree, const struct lyd_node *cur_node, struct lyd_value *value, const struct lysc_type *type)
{
char *errmsg;
struct ly_set *targets = NULL;
LY_ERR ret = LY_SUCCESS;
struct lysc_type_leafref *lref;
struct lysc_type_union *un;
LY_ARRAY_COUNT_TYPE u;
uint32_t i;
struct lyd_node_term *leafref_node = (struct lyd_node_term *)cur_node;

if (type->basetype == LY_TYPE_LEAFREF) {
lref = (struct lysc_type_leafref *)type;
ly_set_free(targets, NULL);
if (lyplg_type_resolve_leafref(lref, cur_node, value, tree, NULL, &targets, &errmsg)) {
/* leafref target not found */
free(errmsg);
} else {
/* leafref target found, link it */
for (i = 0; i < targets->count; ++i) {
if (targets->dnodes[i]->schema->nodetype & LYD_NODE_TERM) {
ret = lyd_link_leafref_node((struct lyd_node_term *)targets->dnodes[i], leafref_node);
LY_CHECK_GOTO(ret, cleanup);
}
}
}
} else if (type->basetype == LY_TYPE_UNION) {
un = (struct lysc_type_union *)type;
LY_ARRAY_FOR(un->types, u) {
ret = lyd_leafref_link_node_tree_type(tree, cur_node, &leafref_node->value.subvalue->value, un->types[u]);
LY_CHECK_GOTO(ret, cleanup)
}
}

cleanup:
ly_set_free(targets, NULL);
return ret;
}

LIBYANG_API_DEF LY_ERR
lyd_leafref_link_node_tree(const struct lyd_node *tree)
{
const struct lyd_node *sibling, *elem;
struct ly_set *targets = NULL;
char *errmsg;
struct lyd_node_term *leafref_node;
struct lyd_node_term *cur_node;
struct lysc_node_leaf *leaf_schema;
struct lysc_type_leafref *lref;
LY_ERR ret = LY_SUCCESS;
uint32_t i;

LY_CHECK_ARG_RET(NULL, tree, LY_EINVAL);

Expand All @@ -3846,33 +3894,15 @@ lyd_leafref_link_node_tree(const struct lyd_node *tree)
LY_LIST_FOR(tree, sibling) {
LYD_TREE_DFS_BEGIN(sibling, elem) {
if (elem->schema && (elem->schema->nodetype & LYD_NODE_TERM)) {
leafref_node = (struct lyd_node_term *)elem;
leaf_schema = (struct lysc_node_leaf *)elem->schema;

if (leaf_schema->type->basetype == LY_TYPE_LEAFREF) {
lref = (struct lysc_type_leafref *)leaf_schema->type;
ly_set_free(targets, NULL);
if (lyplg_type_resolve_leafref(lref, elem, &leafref_node->value, tree, NULL, &targets, &errmsg)) {
/* leafref target not found */
free(errmsg);
} else {
/* leafref target found, link it */
for (i = 0; i < targets->count; ++i) {
if (targets->dnodes[i]->schema->nodetype & LYD_NODE_TERM) {
ret = lyd_link_leafref_node((struct lyd_node_term *)targets->dnodes[i], leafref_node);
LY_CHECK_GOTO(ret, cleanup);
}
}
}
}
cur_node = (struct lyd_node_term *)elem;
LY_CHECK_RET(lyd_leafref_link_node_tree_type(tree, elem, &cur_node->value, leaf_schema->type));
}
LYD_TREE_DFS_END(sibling, elem);
}
}

cleanup:
ly_set_free(targets, NULL);
return ret;
return LY_SUCCESS;
}

LY_ERR
Expand Down
56 changes: 46 additions & 10 deletions tests/utests/data/test_tree_data.c
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,7 @@ static void
test_data_leafref_nodes(void **state)
{
struct lyd_node *tree, *iter;
struct lyd_node_term *target_node = NULL, *leafref_node;
struct lyd_node_term *target_node = NULL, *leafref_node, *leafref_node2;
const struct lyd_leafref_links_rec *rec;
const char *schema, *data, *value;

Expand All @@ -622,6 +622,14 @@ test_data_leafref_nodes(void **state)
" path \"../ll\";"
" }"
" }"
" leaf ref3 {"
" type union {"
" type leafref {"
" path \"../ll\";"
" }"
" type string;"
" }"
" }"
"}";

UTEST_ADD_MODULE(schema, LYS_IN_YANG, NULL, NULL);
Expand All @@ -630,11 +638,12 @@ test_data_leafref_nodes(void **state)
"{"
" \"test-data-hash:ll\": [\"qwe\", \"asd\"],"
" \"test-data-hash:c1\": { \"ref1\": \"qwe\"},"
" \"test-data-hash:ref2\": \"asd\""
" \"test-data-hash:ref2\": \"asd\","
" \"test-data-hash:ref3\": \"asd\""
"}";

/* The run must not crash due to the assert that checks the hash. */
CHECK_PARSE_LYD_PARAM(data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
CHECK_PARSE_LYD_PARAM(data, LYD_JSON, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_SUCCESS, tree);
LY_LIST_FOR(tree, iter) {
if (strcmp(iter->schema->name, "ll") == 0) {
value = lyd_get_value(iter);
Expand All @@ -645,46 +654,73 @@ test_data_leafref_nodes(void **state)
if (strcmp(iter->schema->name, "ref2") == 0) {
leafref_node = (struct lyd_node_term *)iter;
}
if (strcmp(iter->schema->name, "ref3") == 0) {
leafref_node2 = (struct lyd_node_term *)iter;
}
}

/* verify state after leafref plugin validation */
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
assert_ptr_equal(rec->leafref_nodes[0], leafref_node);
assert_int_equal(2, LY_ARRAY_COUNT(rec->leafref_nodes));
assert_ptr_equal(rec->leafref_nodes[1], leafref_node);
assert_ptr_equal(rec->leafref_nodes[0], leafref_node2);
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(leafref_node, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->target_nodes));
assert_ptr_equal(rec->target_nodes[0], target_node);
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(leafref_node2, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->target_nodes));
assert_ptr_equal(rec->target_nodes[0], target_node);
/* value modification of target */
assert_int_equal(LY_SUCCESS, lyd_change_term((struct lyd_node *)target_node, "ASD"));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(target_node, &rec));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(leafref_node, &rec));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(leafref_node2, &rec));
/* change back to original value */
assert_int_equal(LY_SUCCESS, lyd_change_term((struct lyd_node *)target_node, "asd"));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(target_node, &rec));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(leafref_node, &rec));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(leafref_node2, &rec));
/* linking the whole tree again */
assert_int_equal(LY_SUCCESS, lyd_leafref_link_node_tree(tree));
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
assert_int_equal(2, LY_ARRAY_COUNT(rec->leafref_nodes));
assert_ptr_equal(rec->leafref_nodes[0], leafref_node);
assert_ptr_equal(rec->leafref_nodes[1], leafref_node2);
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(leafref_node, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->target_nodes));
assert_ptr_equal(rec->target_nodes[0], target_node);
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(leafref_node2, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->target_nodes));
assert_ptr_equal(rec->target_nodes[0], target_node);
/* value modification of leafref */
assert_int_equal(LY_SUCCESS, lyd_change_term((struct lyd_node *)leafref_node, "qwe"));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(target_node, &rec));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(leafref_node, &rec));
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
assert_ptr_equal(rec->leafref_nodes[0], leafref_node2);
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(leafref_node2, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->target_nodes));
assert_ptr_equal(rec->target_nodes[0], target_node);
assert_int_equal(LY_SUCCESS, lyd_change_term((struct lyd_node *)leafref_node, "asd"));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(target_node, &rec));
assert_int_equal(LY_ENOTFOUND, lyd_leafref_get_links(leafref_node, &rec));
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
assert_ptr_equal(rec->leafref_nodes[0], leafref_node2);
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(leafref_node2, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->target_nodes));
assert_ptr_equal(rec->target_nodes[0], target_node);
/* linking the whole tree again */
assert_int_equal(LY_SUCCESS, lyd_leafref_link_node_tree(tree));
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(target_node, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->leafref_nodes));
assert_ptr_equal(rec->leafref_nodes[0], leafref_node);
assert_int_equal(2, LY_ARRAY_COUNT(rec->leafref_nodes));
assert_ptr_equal(rec->leafref_nodes[1], leafref_node);
assert_ptr_equal(rec->leafref_nodes[0], leafref_node2);
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(leafref_node, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->target_nodes));
assert_ptr_equal(rec->target_nodes[0], target_node);
assert_int_equal(LY_SUCCESS, lyd_leafref_get_links(leafref_node2, &rec));
assert_int_equal(1, LY_ARRAY_COUNT(rec->target_nodes));
assert_ptr_equal(rec->target_nodes[0], target_node);
/* freeing whole tree */
lyd_free_all(tree);
}
Expand Down