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
38 changes: 38 additions & 0 deletions src/printer_sid.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ struct sid_collect_data {
uint64_t count; /**< Number of items collected so far; exceeding @p max, surplus items are only counted. */
uint64_t max; /**< Maximum number of items (capacity of the array). */
struct ly_ctx *ctx; /**< libyang context used for error logging. */
const struct lys_module *module; /**< Module whose nodes are collected; used to attribute augmented nodes to their defining module. */
};

/**
Expand Down Expand Up @@ -178,6 +179,13 @@ collect_data_cb(struct lysc_node *node, void *data, ly_bool *UNUSED(dfs_continue
return LY_SUCCESS; /* choice/case get no item, but their subtree is still traversed */
}

/* collect only nodes defined by the module being processed; when another
* module's tree is traversed this keeps exactly the nodes augmented in by
* the processed module and skips the target module's own nodes */
if (node->module != collect_data->module) {
return LY_SUCCESS;
}

path = sid_node_path(node);
LY_CHECK_ERR_RET(!path, LOGMEM(collect_data->ctx), LY_EMEM);

Expand Down Expand Up @@ -343,12 +351,42 @@ sid_collect_items(struct sid_collect_data *callback_data, const struct lys_modul
LY_CHECK_RET((rc = sid_item_add(callback_data, "feature", feature->name)), rc);
}

/* collect_data_cb attributes nodes to their defining module, so foreign
nodes are skipped whenever another module's tree is traversed below */
callback_data->module = module;

/* data namespace: walk the entire compiled schema tree depth-first.
lysc_module_dfs_full traverses all nodes including RPCs, actions,
notifications, input, output, choice and case nodes. sid_node_path() builds the
RFC 9595 schema-node-path identifiers (choice/case names omitted). */
LY_CHECK_RET((rc = lysc_module_dfs_full(module, collect_data_cb, callback_data)), rc);

/* data namespace: nodes that this module augments into other modules live in
the target modules' trees (RFC 9595 still assigns them to this module's .sid).
Traverse every context module that lists this module in its augmented_by and
collect the nodes defined here (collect_data_cb filters by defining module). */
{
const struct lys_module *aug_target;
uint32_t mod_idx = 0;

while ((aug_target = ly_ctx_get_module_iter(module->ctx, &mod_idx))) {
ly_bool augmented = 0;

if ((aug_target == module) || !aug_target->compiled) {
continue;
}
LY_ARRAY_FOR(aug_target->augmented_by, i) {
if (aug_target->augmented_by[i] == module) {
augmented = 1;
break;
}
}
if (augmented) {
LY_CHECK_RET((rc = lysc_module_dfs_full(aug_target, collect_data_cb, callback_data)), rc);
}
}
}

/* data namespace: also traverse the data trees of compiled top-level extension
instances that define their own data tree outside the standard module trees
(rc:yang-data, sx:structure); the top-level data node is obtained from the
Expand Down
73 changes: 73 additions & 0 deletions tests/utests/schema/test_printer_sid.c
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,78 @@ test_exts(void **state)
lyd_free_all(sid_file);
}

/**
* @brief Test case: augment coverage. A module's .sid file must include the data
* nodes it augments into another module (RFC 9595), and a module's own .sid must
* not include nodes augmented into it by other modules.
*/
static void
test_augment(void **state)
{
struct lys_module *base, *aug;
struct lyd_node *sid_file = NULL;
static const char *mod_base =
"module b1 {\n"
" yang-version 1.1;\n"
" namespace \"urn:b1\";\n"
" prefix b1;\n"
" revision 2024-01-01;\n"
" container cont {\n"
" leaf l { type string; }\n"
" }\n"
"}\n";
static const char *mod_aug =
"module a1 {\n"
" yang-version 1.1;\n"
" namespace \"urn:a1\";\n"
" prefix a1;\n"
" import b1 { prefix b1; }\n"
" revision 2024-01-01;\n"
" augment \"/b1:cont\" {\n"
" leaf x { type string; }\n"
" }\n"
"}\n";

UTEST_ADD_MODULE(mod_base, LYS_IN_YANG, NULL, &base);
UTEST_ADD_MODULE(mod_aug, LYS_IN_YANG, NULL, &aug);
assert_non_null(ly_ctx_load_module(_UC->ctx, "ietf-sid-file", NULL, NULL));

/* the augmenting module's .sid contains the node it augments in: /b1:cont/a1:x */
assert_int_equal(LY_SUCCESS, lys_sid_gen(aug, 100, 2, LYS_SID_FILE_UNPUBLISHED, "d", &sid_file));
assert_non_null(sid_file);
check_json_tree(sid_file,
"{\"ietf-sid-file:sid-file\":{"
"\"module-name\":\"a1\","
"\"module-revision\":\"2024-01-01\","
"\"sid-file-status\":\"unpublished\","
"\"description\":\"d\","
"\"dependency-revision\":[{\"module-name\":\"b1\",\"module-revision\":\"2024-01-01\"}],"
"\"assignment-range\":[{\"entry-point\":\"100\",\"size\":\"2\"}],"
"\"item\":["
"{\"namespace\":\"module\",\"identifier\":\"a1\",\"status\":\"unstable\",\"sid\":\"100\"},"
"{\"namespace\":\"data\",\"identifier\":\"/b1:cont/a1:x\",\"status\":\"unstable\",\"sid\":\"101\"}"
"]}}");
lyd_free_all(sid_file);
sid_file = NULL;

/* the base module's own .sid must not contain the node augmented in by a1 */
assert_int_equal(LY_SUCCESS, lys_sid_gen(base, 100, 3, LYS_SID_FILE_UNPUBLISHED, "d", &sid_file));
assert_non_null(sid_file);
check_json_tree(sid_file,
"{\"ietf-sid-file:sid-file\":{"
"\"module-name\":\"b1\","
"\"module-revision\":\"2024-01-01\","
"\"sid-file-status\":\"unpublished\","
"\"description\":\"d\","
"\"assignment-range\":[{\"entry-point\":\"100\",\"size\":\"3\"}],"
"\"item\":["
"{\"namespace\":\"module\",\"identifier\":\"b1\",\"status\":\"unstable\",\"sid\":\"100\"},"
"{\"namespace\":\"data\",\"identifier\":\"/b1:cont\",\"status\":\"unstable\",\"sid\":\"101\"},"
"{\"namespace\":\"data\",\"identifier\":\"/b1:cont/l\",\"status\":\"unstable\",\"sid\":\"102\"}"
"]}}");
lyd_free_all(sid_file);
}

int
main(void)
{
Expand All @@ -461,6 +533,7 @@ main(void)
UTEST(test_gen),
UTEST(test_flow),
UTEST(test_exts),
UTEST(test_augment),
};

return cmocka_run_group_tests(tests, NULL, NULL);
Expand Down
Loading