diff --git a/CHANGELOG.md b/CHANGELOG.md index 5fd3cc39..d9396112 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -66,6 +66,7 @@ Developers may need to change their code ### Corrected Bugs +* Fixed: [Choice and Leafref](https://github.com/clicon/clixon/issues/469) * Fixed: [Problem deleting non-last list element if ordered-by user](https://github.com/clicon/clixon/issues/475) * Fixed: [Tab completion mounted devices with lists](https://github.com/clicon/clixon-controller/issues/72) * Fixed: kill-session cleanup when client none existant, and for all db:s diff --git a/lib/src/clixon_path.c b/lib/src/clixon_path.c index 61a834b5..147f2078 100644 --- a/lib/src/clixon_path.c +++ b/lib/src/clixon_path.c @@ -255,8 +255,9 @@ clixon_path_print(FILE *f, /*! Given an XML node, return root node * * A root node is an ancestor xr of x with one or both of the following properties - * - its XML parent is NULL parent, - * - its associated yang specification's parent is a yang module. + * (1) its XML parent is NULL parent, + * (2) its associated yang specification's parent is a yang module. + * Note that if there are no yang-specs, only (1) applies * @param[in] x XML node * @param[out] xr XML root * @retval 0 OK @@ -270,13 +271,21 @@ xml_yang_root(cxobj *x, yang_stmt *yp; while ((xp = xml_parent(x)) != NULL){ - if ((y = xml_spec(x)) != NULL && - (yp = yang_parent_get(y)) != NULL) + if ((y = xml_spec(x)) != NULL){ + while ((yp = yang_parent_get(y)) != NULL){ + if (yang_datanode(yp)) + break; + if (yang_keyword_get(yp) == Y_MODULE || + yang_keyword_get(yp) == Y_SUBMODULE) + break; + y = yp; + } /* Actually, maybe only the Y_MODULE clause is relevant */ if (yp==NULL || yang_keyword_get(yp) == Y_MODULE || yang_keyword_get(yp) == Y_SUBMODULE) break; /* x is the root */ + } x = xp; } *xr = x; diff --git a/lib/src/clixon_xpath_yang.c b/lib/src/clixon_xpath_yang.c index db596f19..9a0674a0 100644 --- a/lib/src/clixon_xpath_yang.c +++ b/lib/src/clixon_xpath_yang.c @@ -195,7 +195,23 @@ xp_yang_eval_step(xp_yang_ctx *xy0, } /* nodetest xs_type */ break; case A_PARENT: - xy->xy_node = yang_parent_get(ys); + { + yang_stmt *yp; + ys1 = ys; + while ((yp = yang_parent_get(ys1)) != NULL){ + if (yang_datanode(yp)){ + ys1 = yp; + break; + } + if (yang_keyword_get(yp) == Y_MODULE || + yang_keyword_get(yp) == Y_SUBMODULE){ + ys1 = yp; + break; + } + ys1 = yp; + } + xy->xy_node = ys1; + } break; default: clixon_err(OE_YANG, 0, "Invalid path-arg step: %s", diff --git a/test/test_leafref_choice.sh b/test/test_leafref_choice.sh new file mode 100755 index 00000000..b10b13ae --- /dev/null +++ b/test/test_leafref_choice.sh @@ -0,0 +1,141 @@ +#!/usr/bin/env bash +# Yang leafref + choice test +# See https://github.com/clicon/clixon/issues/469 + +# Magic line must be first in script (see README.md) +s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi + +APPNAME=example + +cfg=$dir/conf_yang.xml +fyang=$dir/leafref.yang + +cat < $cfg + + $cfg + $dir + ${YANG_INSTALLDIR} + $IETFRFC + $fyang + /usr/local/lib/$APPNAME/clispec + /usr/local/lib/$APPNAME/cli + $APPNAME + /usr/local/var/run/$APPNAME.sock + /usr/local/var/run/$APPNAME.pidfile + $dir + +EOF + +cat < $fyang +module example{ + yang-version 1.1; + namespace "urn:example:clixon"; + prefix ex; + grouping fruits-and-flowers{ + list fruit { + key "name"; + leaf name { + type string; + } + } + list flower { + key "name"; + leaf name { + type string; + } + } + choice myChoice { + description "Fruit or Flowers"; + case fruit { + leaf fruit-name { + description "Fruit name"; + type leafref { + path "../fruit/name"; + } + } + } + case flower { + leaf flower-name { + description "Flower name"; + type leafref { + path "../flower/name"; + } + } + } + } + } + container c { + uses fruits-and-flowers; + } + uses fruits-and-flowers; +} +EOF + +# Leafref and choice test +# Args: +# 1: prefix +function testrun() +{ + prefix=$1 + + new "add fruit" + expectpart "$($clixon_cli -1f $cfg set $prefix fruit apple)" 0 "^$" + + new "add fruit" + expectpart "$($clixon_cli -1f $cfg set $prefix fruit orange)" 0 "^$" + + new "add flower" + expectpart "$($clixon_cli -1f $cfg set $prefix flower daisy)" 0 "^$" + + new "add flower" + expectpart "$($clixon_cli -1f $cfg set $prefix flower rose)" 0 "^$" + + new "commit" + expectpart "$($clixon_cli -1f $cfg commit)" 0 "^$" + + new "expand fruit leafref" + expectpart "$(echo "set $prefix fruit-name ?" | $clixon_cli -f $cfg -o CLICON_CLI_EXPAND_LEAFREF=true 2> /dev/null)" 0 apple orange + + new "add fruit-name" + expectpart "$($clixon_cli -1f $cfg set $prefix fruit-name apple)" 0 "^$" + + new "validate" + expectpart "$($clixon_cli -1f $cfg validate)" 0 "^$" +} + +new "test params: -f $cfg" + +if [ $BE -ne 0 ]; then + new "kill old backend" + sudo clixon_backend -zf $cfg + if [ $? -ne 0 ]; then + err + fi + new "start backend -s init -f $cfg" + start_backend -s init -f $cfg +fi + +new "wait backend" +wait_backend + +new "Test top-level" +testrun "" + +new "Test in container" +testrun "c " + +if [ $BE -ne 0 ]; then + new "Kill backend" + # Check if premature kill + pid=$(pgrep -u root -f clixon_backend) + if [ -z "$pid" ]; then + err "backend already dead" + fi + # kill backend + stop_backend -f $cfg +fi + +rm -rf $dir + +new "endtest" +endtest