diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f5163f5..91697a20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -57,6 +57,8 @@ * Added libgen.h for baseline() ### Corrected Bugs +* Bugfix: [Nodes from more than one of the choice's branches exist at the same time](https://github.com/clicon/clixon/issues/81) + * Note it may still be possible to load a file with multiple choice elements via netconf, but it will not pass validate. * Bugfix: Default NACM policies applied even if NACM is disabled * [Identityref inside augment statement](https://github.com/clicon/clixon/issues/77) * Yang-stmt enhanced with "shortcut" to original module diff --git a/lib/src/clixon_xml_map.c b/lib/src/clixon_xml_map.c index 408cfac8..09985887 100644 --- a/lib/src/clixon_xml_map.c +++ b/lib/src/clixon_xml_map.c @@ -487,6 +487,50 @@ xml_yang_validate_rpc(cxobj *xrpc, goto done; } +/*! Check if an xml node is a part of a choice and have >1 siblings + * @param[in] xt XML node to be validated + * @param[in] yt xt:s yang statement + * @param[out] cbret Error buffer (set w netconf error if retval == 0) + * @retval 1 Validation OK + * @retval 0 Validation failed (cbret set) + * @retval -1 Error + */ +static int +check_choice(cxobj *xt, + yang_stmt *yt, + cbuf *cbret) +{ + int retval = -1; + yang_node *yc; + yang_stmt *y; + yang_node *yp; + cxobj *x; + cxobj *xp; + + if ((yc = yang_choice(yt)) == NULL) + goto ok; + if ((xp = xml_parent(xt)) == NULL) + goto ok; + x = NULL; /* Find a child with same yang spec */ + while ((x = xml_child_each(xp, x, CX_ELMNT)) != NULL) { + if ((x != xt) && + (y = xml_spec(x)) != NULL && + (yp = yang_choice(y)) != NULL && + yp == (yang_node*)yc){ + if (netconf_bad_element(cbret, "application", xml_name(x), "Element in choice statement already exists") < 0) + goto done; + goto fail; + } + } + ok: + retval = 1; + done: + return retval; + fail: + retval = 0; + goto done; +} + /*! Check if an xml node lacks mandatory children * @param[in] xt XML node to be validated * @param[in] yt xt:s yang statement @@ -623,6 +667,10 @@ xml_yang_validate_add(cxobj *xt, /* if not given by argument (overide) use default link and !Node has a config sub-statement and it is false */ if ((yt = xml_spec(xt)) != NULL && yang_config(yt) != 0){ + if ((ret = check_choice(xt, yt, cbret)) < 0) + goto done; + if (ret == 0) + goto fail; if ((ret = check_mandatory(xt, yt, cbret)) < 0) goto done; if (ret == 0) diff --git a/test/test_choice.sh b/test/test_choice.sh index a281cf54..f1d5192f 100755 --- a/test/test_choice.sh +++ b/test/test_choice.sh @@ -115,6 +115,15 @@ sleep $RCWAIT new "netconf validate empty" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^]]>]]>$" +new "netconf set protocol both udp and tcp" +expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 ']]>]]>' "^]]>]]>$" + +new "netconf validate both udp and tcp fail" +expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^applicationbad-elementudperrorElement in choice statement already exists]]>]]>$" + +new "netconf discard-changes" +expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^]]>]]>$" + new "netconf set empty protocol" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 ']]>]]>' "^]]>]]>$" @@ -139,6 +148,14 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^]]>]]>$" +#-- restconf + +new "restconf DELETE whole datastore" +expectfn 'curl -s -X DELETE http://localhost/restconf/data' 0 "" + +new "restconf set protocol tcp+udp fail" +expecteq "$(curl -s -X PUT http://localhost/restconf/data/system:system/protocol -d '{"system:protocol":{"tcp": null, "udp": null}}')" 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "bad-element","error-info": {"bad-element": "udp"},"error-severity": "error","error-message": "Element in choice statement already exists"}}} ' + new "restconf set protocol tcp" expecteq "$(curl -s -X PUT http://localhost/restconf/data/system:system/protocol -d {\"system:protocol\":{\"tcp\":null}})" 0 "" @@ -146,12 +163,21 @@ new "restconf get protocol tcp" expecteq "$(curl -s -X GET http://localhost/restconf/data/system:system)" 0 '{"system:system": {"protocol": {"tcp": null}}} ' +new "restconf set protocol tcp+udp fail" +expecteq "$(curl -s -X PUT http://localhost/restconf/data/system:system/protocol -d '{"system:protocol":{"tcp": null, "udp": null}}')" 0 '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "bad-element","error-info": {"bad-element": "udp"},"error-severity": "error","error-message": "Element in choice statement already exists"}}} ' + new "cli set protocol udp" expectfn "$clixon_cli -1 -f $cfg -y $fyang -l o set system protocol udp" 0 "^$" new "cli get protocol udp" expectfn "$clixon_cli -1 -f $cfg -y $fyang -l o show configuration cli " 0 "^system protocol udp$" +new "cli change protocol to tcp" +expectfn "$clixon_cli -1 -f $cfg -y $fyang -l o set system protocol tcp" 0 "^$" + +new "cli get protocol tcp" +expectfn "$clixon_cli -1 -f $cfg -y $fyang -l o show configuration cli " 0 "^system protocol tcp$" + new "cli delete all" expectfn "$clixon_cli -1 -f $cfg -y $fyang -l o delete all" 0 "^$" @@ -159,6 +185,15 @@ new "commit" expectfn "$clixon_cli -1 -f $cfg -y $fyang -l o commit" 0 "^$" # Second shorthand (no case) +new "netconf set protocol both udp and tcp" +expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 ']]>]]>' "^]]>]]>$" + +new "netconf validate both udp and tcp fail" +expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^applicationbad-elementudperrorElement in choice statement already exists]]>]]>$" + +new "netconf discard-changes" +expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^]]>]]>$" + new "netconf set shorthand tcp" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 ']]>]]>' "^]]>]]>$"