* xml_cmp() respects 'ordered-by user' for state nodes, which violates RFC 7950 [https://github.com/clicon/clixon/issues/63. (Thanks JDL)

This commit is contained in:
Olof hagsand 2019-02-03 16:19:33 +01:00
parent 376b75328c
commit 02d725b2c0
10 changed files with 85 additions and 53 deletions

View file

@ -142,6 +142,7 @@
* <!DOCTYPE (ie DTD) is not supported. * <!DOCTYPE (ie DTD) is not supported.
### Corrected Bugs ### Corrected Bugs
* xml_cmp() respects 'ordered-by user' for state nodes, which violates RFC 7950 [https://github.com/clicon/clixon/issues/63. (Thanks JDL)
* XML<>JSON conversion problems [https://github.com/clicon/clixon/issues/66] * XML<>JSON conversion problems [https://github.com/clicon/clixon/issues/66]
* CDATA sections stripped from XML when converted to JSON * CDATA sections stripped from XML when converted to JSON
* Restconf returns error when RPC generates "ok" reply [https://github.com/clicon/clixon/issues/69] * Restconf returns error when RPC generates "ok" reply [https://github.com/clicon/clixon/issues/69]

View file

@ -201,6 +201,8 @@ example_statedata(clicon_handle h,
*/ */
if (xml_parse_string("<state xmlns=\"urn:example:clixon\">" if (xml_parse_string("<state xmlns=\"urn:example:clixon\">"
"<op>42</op>" "<op>42</op>"
"<op>41</op>"
"<op>43</op>" /* should not be ordered */
"</state>", NULL, &xstate) < 0) "</state>", NULL, &xstate) < 0)
goto done; goto done;
retval = 0; retval = 0;

View file

@ -40,7 +40,6 @@
* Prototypes * Prototypes
*/ */
int xml_child_spec(cxobj *x, cxobj *xp, yang_spec *yspec, yang_stmt **yp); int xml_child_spec(cxobj *x, cxobj *xp, yang_spec *yspec, yang_stmt **yp);
int xml_cmp(const void* arg1, const void* arg2);
int xml_sort(cxobj *x0, void *arg); int xml_sort(cxobj *x0, void *arg);
cxobj *xml_search(cxobj *x, char *name, int yangi, enum rfc_6020 keyword, int keynr, char **keyvec, char **keyval); cxobj *xml_search(cxobj *x, char *name, int yangi, enum rfc_6020 keyword, int keynr, char **keyvec, char **keyval);
int xml_insert_pos(cxobj *x0, char *name, int yangi, enum rfc_6020 keyword, int xml_insert_pos(cxobj *x0, char *name, int yangi, enum rfc_6020 keyword,

View file

@ -134,7 +134,7 @@ xml_child_spec(cxobj *x,
* @see xml_cmp1 Similar, but for one object * @see xml_cmp1 Similar, but for one object
* @note empty value/NULL is smallest value * @note empty value/NULL is smallest value
*/ */
int static int
xml_cmp(const void* arg1, xml_cmp(const void* arg1,
const void* arg2) const void* arg2)
{ {
@ -162,11 +162,13 @@ xml_cmp(const void* arg1,
if ((equal = yi1-yi2) != 0) if ((equal = yi1-yi2) != 0)
return equal; return equal;
} }
/* Now y1=y2, same Yang spec, can only be list or leaf-list, /* Now y1==y2, same Yang spec, can only be list or leaf-list,
* sort according to key * But first check exceptions, eg config false or ordered-by user
* otherwuse sort according to key
*/ */
if (yang_find((yang_node*)y1, Y_ORDERED_BY, "user") != NULL) if (yang_config(y1)==0 ||
return 0; /* Ordered by user: maintain existing order */ yang_find((yang_node*)y1, Y_ORDERED_BY, "user") != NULL)
return 0; /* Ordered by user or state data : maintain existing order */
switch (y1->ys_keyword){ switch (y1->ys_keyword){
case Y_LEAF_LIST: /* Match with name and value */ case Y_LEAF_LIST: /* Match with name and value */
if ((b1 = xml_body(x1)) == NULL) if ((b1 = xml_body(x1)) == NULL)
@ -262,11 +264,20 @@ xml_cmp1(cxobj *x,
* Assume populated by yang spec. * Assume populated by yang spec.
* @param[in] x0 XML node * @param[in] x0 XML node
* @param[in] arg Dummy so it can be called by xml_apply() * @param[in] arg Dummy so it can be called by xml_apply()
* @retval -1 Error, aborted at first error encounter
* @retval 0 OK, all nodes traversed (subparts may have been skipped)
* @retval 1 OK, aborted on first fn returned 1
* @see xml_apply - typically called by recursive apply function
*/ */
int int
xml_sort(cxobj *x, xml_sort(cxobj *x,
void *arg) void *arg)
{ {
yang_stmt *ys;
/* Abort sort if non-config (=state) data */
if ((ys = xml_spec(x)) != 0 && yang_config(ys)==0)
return 1;
qsort(xml_childvec_get(x), xml_child_nr(x), sizeof(cxobj *), xml_cmp); qsort(xml_childvec_get(x), xml_child_nr(x), sizeof(cxobj *), xml_cmp);
return 0; return 0;
} }
@ -543,7 +554,13 @@ xml_sort_verify(cxobj *x0,
int retval = -1; int retval = -1;
cxobj *x = NULL; cxobj *x = NULL;
cxobj *xprev = NULL; cxobj *xprev = NULL;
yang_stmt *ys;
/* Abort sort if non-config (=state) data */
if ((ys = xml_spec(x0)) != 0 && yang_config(ys)==0){
retval = 1;
goto done;
}
while ((x = xml_child_each(x0, x, -1)) != NULL) { while ((x = xml_child_each(x0, x, -1)) != NULL) {
if (xprev != NULL){ /* Check xprev <= x */ if (xprev != NULL){ /* Check xprev <= x */
if (xml_cmp(&xprev, &x) > 0) if (xml_cmp(&xprev, &x) > 0)

View file

@ -145,7 +145,7 @@ fi
# Note order of features in ietf-netconf yang is alphabetically: candidate, startup, validate, xpath # Note order of features in ietf-netconf yang is alphabetically: candidate, startup, validate, xpath
new "netconf module ietf-netconf" new "netconf module ietf-netconf"
expect="<module><name>ietf-netconf</name><revision>2011-06-01</revision><namespace>urn:ietf:params:xml:ns:netconf:base:1.0</namespace><feature>candidate</feature><feature>startup</feature><feature>validate</feature><feature>xpath</feature><conformance-type>implement</conformance-type></module>" expect="<module><name>ietf-netconf</name><revision>2011-06-01</revision><namespace>urn:ietf:params:xml:ns:netconf:base:1.0</namespace><feature>candidate</feature><feature>validate</feature><feature>startup</feature><feature>xpath</feature><conformance-type>implement</conformance-type></module>"
match=`echo "$ret" | grep -GZo "$expect"` match=`echo "$ret" | grep -GZo "$expect"`
if [ -z "$match" ]; then if [ -z "$match" ]; then
err "$expect" "$ret" err "$expect" "$ret"

View file

@ -152,7 +152,7 @@ sudo su -c "$clixon_restconf -f $cfg -D $DBG -- -a" -s /bin/sh www-data &
sleep $RCWAIT sleep $RCWAIT
new "auth get" new "auth get"
expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/clixon-example:state)" '{"clixon-example:state": {"op": "42"}} expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/clixon-example:state)" '{"clixon-example:state": {"op": ["42","41","43"]}}
' '
new "Set x to 0" new "Set x to 0"

View file

@ -175,7 +175,7 @@ expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/nacm-exam
' '
new "admin read state OK" new "admin read state OK"
expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/clixon-example:state)" '{"clixon-example:state": {"op": "42"}} expecteq "$(curl -u andy:bar -sS -X GET http://localhost/restconf/data/clixon-example:state)" '{"clixon-example:state": {"op": ["42","41","43"]}}
' '
new "admin read top ok (all)" new "admin read top ok (all)"
@ -204,11 +204,11 @@ expecteq "$(curl -u wilma:bar -sS -X GET http://localhost/restconf/data/nacm-exa
' '
new "limit read state OK" new "limit read state OK"
expecteq "$(curl -u wilma:bar -sS -X GET http://localhost/restconf/data/clixon-example:state)" '{"clixon-example:state": {"op": "42"}} expecteq "$(curl -u wilma:bar -sS -X GET http://localhost/restconf/data/clixon-example:state)" '{"clixon-example:state": {"op": ["42","41","43"]}}
' '
new "limit read top ok (part)" new "limit read top ok (part)"
expecteq "$(curl -u wilma:bar -sS -X GET http://localhost/restconf/data)" '{"data": {"clixon-example:translate": [{"k": "key42","value": "val42"},{ "k": "key43","value": "val43"}],"clixon-example:state": {"op": "42"}}} expecteq "$(curl -u wilma:bar -sS -X GET http://localhost/restconf/data)" '{"data": {"clixon-example:translate": [{"k": "key42","value": "val42"},{ "k": "key43","value": "val43"}],"clixon-example:state": {"op": ["42","41","43"]}}}
' '
#user:guest #user:guest

View file

@ -155,7 +155,7 @@ new "netconf edit state operation should fail"
expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><state xmlns="urn:example:clixon"><op>42</op></state></config></edit-config></rpc>]]>]]>' "^<rpc-reply><rpc-error><error-type>protocol</error-type><error-tag>invalid-value</error-tag>" expecteof "$clixon_netconf -qf $cfg" 0 '<rpc><edit-config><target><candidate/></target><config><state xmlns="urn:example:clixon"><op>42</op></state></config></edit-config></rpc>]]>]]>' "^<rpc-reply><rpc-error><error-type>protocol</error-type><error-tag>invalid-value</error-tag>"
new "netconf get state operation" new "netconf get state operation"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get><filter type=\"xpath\" select=\"/state\"/></get></rpc>]]>]]>" '^<rpc-reply><data><state xmlns="urn:example:clixon"><op>42</op></state></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><get><filter type=\"xpath\" select=\"/state\"/></get></rpc>]]>]]>" '^<rpc-reply><data><state xmlns="urn:example:clixon"><op>42</op><op>41</op><op>43</op></state></data></rpc-reply>]]>]]>$'
new "netconf lock/unlock" new "netconf lock/unlock"
expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><lock><target><candidate/></target></lock></rpc>]]>]]><rpc><unlock><target><candidate/></target></unlock></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]><rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg" 0 "<rpc><lock><target><candidate/></target></lock></rpc>]]>]]><rpc><unlock><target><candidate/></target></unlock></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]><rpc-reply><ok/></rpc-reply>]]>]]>$"

View file

@ -10,6 +10,7 @@ APPNAME=example
. ./lib.sh . ./lib.sh
cfg=$dir/conf_yang.xml cfg=$dir/conf_yang.xml
fyang=$dir/order.yang fyang=$dir/order.yang
tmp=$dir/tmp.x
# For memcheck # For memcheck
# clixon_netconf="valgrind --leak-check=full --show-leak-kinds=all clixon_netconf" # clixon_netconf="valgrind --leak-check=full --show-leak-kinds=all clixon_netconf"
@ -30,6 +31,7 @@ cat <<EOF > $cfg
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR> <CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE> <CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK> <CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
<CLICON_BACKEND_DIR>/usr/local/lib/example/backend</CLICON_BACKEND_DIR>
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE> <CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
<CLICON_CLI_GENMODEL_COMPLETION>1</CLICON_CLI_GENMODEL_COMPLETION> <CLICON_CLI_GENMODEL_COMPLETION>1</CLICON_CLI_GENMODEL_COMPLETION>
<CLICON_XMLDB_DIR>$dbdir</CLICON_XMLDB_DIR> <CLICON_XMLDB_DIR>$dbdir</CLICON_XMLDB_DIR>
@ -39,10 +41,13 @@ cat <<EOF > $cfg
EOF EOF
cat <<EOF > $fyang cat <<EOF > $fyang
module example{ module order-example{
yang-version 1.1; yang-version 1.1;
namespace "urn:example:clixon"; namespace "urn:example:order";
prefix ex; prefix ex;
import clixon-example { /* for state callback */
prefix ex;
}
container c{ container c{
leaf d{ leaf d{
type string; type string;
@ -86,24 +91,24 @@ rm -f $dbdir/candidate_db
# alt # alt
cat <<EOF > $dbdir/running_db cat <<EOF > $dbdir/running_db
<config> <config>
<y0 xmlns="urn:example:clixon">d</y0> <y0 xmlns="urn:example:order">d</y0>
<y1 xmlns="urn:example:clixon">d</y1> <y1 xmlns="urn:example:order">d</y1>
<y2 xmlns="urn:example:clixon"><k>d</k><a>bar</a></y2> <y2 xmlns="urn:example:order"><k>d</k><a>bar</a></y2>
<y3 xmlns="urn:example:clixon"><k>d</k><a>bar</a></y3> <y3 xmlns="urn:example:order"><k>d</k><a>bar</a></y3>
<y0 xmlns="urn:example:clixon">b</y0> <y0 xmlns="urn:example:order">b</y0>
<y1 xmlns="urn:example:clixon">b</y1> <y1 xmlns="urn:example:order">b</y1>
<c xmlns="urn:example:clixon"><d>hej</d></c> <c xmlns="urn:example:order"><d>hej</d></c>
<y0 xmlns="urn:example:clixon">c</y0> <y0 xmlns="urn:example:order">c</y0>
<y1 xmlns="urn:example:clixon">c</y1> <y1 xmlns="urn:example:order">c</y1>
<y2 xmlns="urn:example:clixon"><k>a</k><a>bar</a></y2> <y2 xmlns="urn:example:order"><k>a</k><a>bar</a></y2>
<y3 xmlns="urn:example:clixon"><k>a</k><a>bar</a></y3> <y3 xmlns="urn:example:order"><k>a</k><a>bar</a></y3>
<l xmlns="urn:example:clixon">hopp</l> <l xmlns="urn:example:order">hopp</l>
<y0 xmlns="urn:example:clixon">a</y0> <y0 xmlns="urn:example:order">a</y0>
<y1 xmlns="urn:example:clixon">a</y1> <y1 xmlns="urn:example:order">a</y1>
<y2 xmlns="urn:example:clixon"><k>c</k><a>bar</a></y2> <y2 xmlns="urn:example:order"><k>c</k><a>bar</a></y2>
<y3 xmlns="urn:example:clixon"><k>c</k><a>bar</a></y3> <y3 xmlns="urn:example:order"><k>c</k><a>bar</a></y3>
<y2 xmlns="urn:example:clixon"><k>b</k><a>bar</a></y2> <y2 xmlns="urn:example:order"><k>b</k><a>bar</a></y2>
<y3 xmlns="urn:example:clixon"><k>b</k><a>bar</a></y3> <y3 xmlns="urn:example:order"><k>b</k><a>bar</a></y3>
</config> </config>
EOF EOF
@ -122,21 +127,28 @@ if [ $BE -ne 0 ]; then
fi fi
fi fi
# STATE (should not be ordered)
new "state data (should be unordered: 42,41,43)"
cat <<EOF > $tmp
<rpc><get><filter type="xpath" select="state"/></get></rpc>]]>]]>
EOF
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "$(cat $tmp)" '<rpc-reply><data><state xmlns="urn:example:clixon"><op>42</op><op>41</op><op>43</op></state></data></rpc-reply>]]>]]>'
# Check as file # Check as file
new "verify running from start, should be: c,l,y0,y1,y2,y3; y1 and y3 sorted. Note this fails if CLICON_XML_SORT set to false" new "verify running from start, should be: c,l,y0,y1,y2,y3; y1 and y3 sorted. Note this fails if CLICON_XML_SORT set to false"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><running/></source></get-config></rpc>]]>]]>' '^<rpc-reply><data><c xmlns="urn:example:clixon"><d>hej</d></c><l xmlns="urn:example:clixon">hopp</l><y0 xmlns="urn:example:clixon">d</y0><y0 xmlns="urn:example:clixon">b</y0><y0 xmlns="urn:example:clixon">c</y0><y0 xmlns="urn:example:clixon">a</y0><y1 xmlns="urn:example:clixon">a</y1><y1 xmlns="urn:example:clixon">b</y1><y1 xmlns="urn:example:clixon">c</y1><y1 xmlns="urn:example:clixon">d</y1><y2 xmlns="urn:example:clixon"><k>d</k><a>bar</a></y2><y2 xmlns="urn:example:clixon"><k>a</k><a>bar</a></y2><y2 xmlns="urn:example:clixon"><k>c</k><a>bar</a></y2><y2 xmlns="urn:example:clixon"><k>b</k><a>bar</a></y2><y3 xmlns="urn:example:clixon"><k>a</k><a>bar</a></y3><y3 xmlns="urn:example:clixon"><k>b</k><a>bar</a></y3><y3 xmlns="urn:example:clixon"><k>c</k><a>bar</a></y3><y3 xmlns="urn:example:clixon"><k>d</k><a>bar</a></y3></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><running/></source></get-config></rpc>]]>]]>' '^<rpc-reply><data><c xmlns="urn:example:order"><d>hej</d></c><l xmlns="urn:example:order">hopp</l><y0 xmlns="urn:example:order">d</y0><y0 xmlns="urn:example:order">b</y0><y0 xmlns="urn:example:order">c</y0><y0 xmlns="urn:example:order">a</y0><y1 xmlns="urn:example:order">a</y1><y1 xmlns="urn:example:order">b</y1><y1 xmlns="urn:example:order">c</y1><y1 xmlns="urn:example:order">d</y1><y2 xmlns="urn:example:order"><k>d</k><a>bar</a></y2><y2 xmlns="urn:example:order"><k>a</k><a>bar</a></y2><y2 xmlns="urn:example:order"><k>c</k><a>bar</a></y2><y2 xmlns="urn:example:order"><k>b</k><a>bar</a></y2><y3 xmlns="urn:example:order"><k>a</k><a>bar</a></y3><y3 xmlns="urn:example:order"><k>b</k><a>bar</a></y3><y3 xmlns="urn:example:order"><k>c</k><a>bar</a></y3><y3 xmlns="urn:example:order"><k>d</k><a>bar</a></y3><interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"><interface><name>lo</name><type>ex:loopback</type><enabled>true</enabled></interface></interfaces></data></rpc-reply>]]>]]>$'
new "get each ordered-by user leaf-list" new "get each ordered-by user leaf-list"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y2[k='a']\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><y2 xmlns="urn:example:clixon"><k>a</k><a>bar</a></y2></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y2[k='a']\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><y2 xmlns="urn:example:order"><k>a</k><a>bar</a></y2></data></rpc-reply>]]>]]>$'
new "get each ordered-by user leaf-list" new "get each ordered-by user leaf-list"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y3[k='a']\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><y3 xmlns="urn:example:clixon"><k>a</k><a>bar</a></y3></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y3[k='a']\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><y3 xmlns="urn:example:order"><k>a</k><a>bar</a></y3></data></rpc-reply>]]>]]>$'
new "get each ordered-by user leaf-list" new "get each ordered-by user leaf-list"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y2[k='b']\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><y2 xmlns="urn:example:clixon"><k>b</k><a>bar</a></y2></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y2[k='b']\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><y2 xmlns="urn:example:order"><k>b</k><a>bar</a></y2></data></rpc-reply>]]>]]>$'
new "get each ordered-by user leaf-list" new "get each ordered-by user leaf-list"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y3[k='b']\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><y3 xmlns="urn:example:clixon"><k>b</k><a>bar</a></y3></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><get-config><source><running/></source><filter type=\"xpath\" select=\"/y3[k='b']\"/></get-config></rpc>]]>]]>" '^<rpc-reply><data><y3 xmlns="urn:example:order"><k>b</k><a>bar</a></y3></data></rpc-reply>]]>]]>$'
new "delete candidate" new "delete candidate"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><default-operation>none</default-operation><config operation="delete"/></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><default-operation>none</default-operation><config operation="delete"/></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
@ -144,33 +156,33 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><can
# LEAF_LISTS # LEAF_LISTS
new "add two entries (c,b) to leaf-list user order" new "add two entries (c,b) to leaf-list user order"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><y0 xmlns="urn:example:clixon">c</y0><y0 xmlns="urn:example:clixon">b</y0></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><y0 xmlns="urn:example:order">c</y0><y0 xmlns="urn:example:order">b</y0></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "add one entry (a) to leaf-list user order" new "add one entry (a) to leaf-list user order"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><y0 xmlns="urn:example:clixon">a</y0></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><y0 xmlns="urn:example:order">a</y0></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf commit" new "netconf commit"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "add one entry (0) to leaf-list user order after commit" new "add one entry (0) to leaf-list user order after commit"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><y0 xmlns="urn:example:clixon">0</y0></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><y0 xmlns="urn:example:order">0</y0></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf commit" new "netconf commit"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><commit/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "verify leaf-list user order in running (as entered: c,b,a,0)" new "verify leaf-list user order in running (as entered: c,b,a,0)"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><running/></source><filter type="xpath" select="/y0"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><y0 xmlns="urn:example:clixon">c</y0><y0 xmlns="urn:example:clixon">b</y0><y0 xmlns="urn:example:clixon">a</y0><y0 xmlns="urn:example:clixon">0</y0></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><running/></source><filter type="xpath" select="/y0"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><y0 xmlns="urn:example:order">c</y0><y0 xmlns="urn:example:order">b</y0><y0 xmlns="urn:example:order">a</y0><y0 xmlns="urn:example:order">0</y0></data></rpc-reply>]]>]]>$'
# LISTS # LISTS
new "add two entries to list user order" new "add two entries to list user order"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><y2 xmlns="urn:example:clixon"><k>c</k><a>bar</a></y2><y2 xmlns="urn:example:clixon"><k>b</k><a>foo</a></y2></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><y2 xmlns="urn:example:order"><k>c</k><a>bar</a></y2><y2 xmlns="urn:example:order"><k>b</k><a>foo</a></y2></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "add one entry to list user order" new "add one entry to list user order"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><y2 xmlns="urn:example:clixon"><k>a</k><a>fie</a></y2></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><y2 xmlns="urn:example:order"><k>a</k><a>fie</a></y2></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "verify list user order (as entered)" new "verify list user order (as entered)"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/y2"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><y2 xmlns="urn:example:clixon"><k>c</k><a>bar</a></y2><y2 xmlns="urn:example:clixon"><k>b</k><a>foo</a></y2><y2 xmlns="urn:example:clixon"><k>a</k><a>fie</a></y2></data></rpc-reply>]]>]]>$' expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><get-config><source><candidate/></source><filter type="xpath" select="/y2"/></get-config></rpc>]]>]]>' '^<rpc-reply><data><y2 xmlns="urn:example:order"><k>c</k><a>bar</a></y2><y2 xmlns="urn:example:order"><k>b</k><a>foo</a></y2><y2 xmlns="urn:example:order"><k>a</k><a>fie</a></y2></data></rpc-reply>]]>]]>$'
if [ $BE -eq 0 ]; then if [ $BE -eq 0 ]; then
exit # BE exit # BE

View file

@ -31,7 +31,7 @@ cat <<EOF > $cfg
EOF EOF
# This is a fixed 'state' implemented in routing_backend. It is assumed to be always there # This is a fixed 'state' implemented in routing_backend. It is assumed to be always there
state='{"clixon-example:state": {"op": "42"}}' state='{"clixon-example:state": {"op": ["42","41","43"]}} '
new "test params: -f $cfg" new "test params: -f $cfg"
if [ $BE -ne 0 ]; then if [ $BE -ne 0 ]; then
@ -113,11 +113,11 @@ new "restconf empty rpc with extra args (should fail)"
expecteq "$(curl -s -X POST -d {\"clixon-example:input\":{\"extra\":null}} http://localhost/restconf/operations/clixon-example:empty)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "unknown-element","error-info": {"bad-element": "extra"},"error-severity": "error"}}} ' expecteq "$(curl -s -X POST -d {\"clixon-example:input\":{\"extra\":null}} http://localhost/restconf/operations/clixon-example:empty)" '{"ietf-restconf:errors" : {"error": {"error-type": "application","error-tag": "unknown-element","error-info": {"bad-element": "extra"},"error-severity": "error"}}} '
new "restconf get empty config + state json" new "restconf get empty config + state json"
expecteq "$(curl -sSG http://localhost/restconf/data/clixon-example:state)" '{"clixon-example:state": {"op": "42"}} expecteq "$(curl -sSG http://localhost/restconf/data/clixon-example:state)" '{"clixon-example:state": {"op": ["42","41","43"]}}
' '
new "restconf get empty config + state json + module" new "restconf get empty config + state json + module"
expecteq "$(curl -sSG http://localhost/restconf/data/clixon-example:state)" '{"clixon-example:state": {"op": "42"}} expecteq "$(curl -sSG http://localhost/restconf/data/clixon-example:state)" '{"clixon-example:state": {"op": ["42","41","43"]}}
' '
new "restconf get empty config + state json with wrong module name" new "restconf get empty config + state json with wrong module name"
@ -125,14 +125,14 @@ expecteq "$(curl -sSG http://localhost/restconf/data/badmodule:state)" '{"ietf-r
new "restconf get empty config + state xml" new "restconf get empty config + state xml"
ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/data/clixon-example:state) ret=$(curl -s -H "Accept: application/yang-data+xml" -G http://localhost/restconf/data/clixon-example:state)
expect='<state xmlns="urn:example:clixon"><op>42</op></state>' expect='<state xmlns="urn:example:clixon"><op>42</op><op>41</op><op>43</op></state>'
match=`echo $ret | grep -EZo "$expect"` match=`echo $ret | grep -EZo "$expect"`
if [ -z "$match" ]; then if [ -z "$match" ]; then
err "$expect" "$ret" err "$expect" "$ret"
fi fi
new "restconf get data/ json" new "restconf get data/ json"
expecteq "$(curl -s -G http://localhost/restconf/data/clixon-example:state/op=42)" '{"clixon-example:op": "42"} expecteq "$(curl -s -G http://localhost/restconf/data/clixon-example:state/op=42)" '{"clixon-example:op": ["42","41","43"]}
' '
new "restconf get state operation eth0 xml" new "restconf get state operation eth0 xml"
@ -145,7 +145,7 @@ if [ -z "$match" ]; then
fi fi
new "restconf get state operation eth0 type json" new "restconf get state operation eth0 type json"
expecteq "$(curl -s -G http://localhost/restconf/data/clixon-example:state/op=42)" '{"clixon-example:op": "42"} expecteq "$(curl -s -G http://localhost/restconf/data/clixon-example:state/op=42)" '{"clixon-example:op": ["42","41","43"]}
' '
new "restconf get state operation eth0 type xml" new "restconf get state operation eth0 type xml"
@ -158,7 +158,7 @@ if [ -z "$match" ]; then
fi fi
new "restconf GET datastore" new "restconf GET datastore"
expecteq "$(curl -s -X GET http://localhost/restconf/data/clixon-example:state)" '{"clixon-example:state": {"op": "42"}} expecteq "$(curl -s -X GET http://localhost/restconf/data/clixon-example:state)" '{"clixon-example:state": {"op": ["42","41","43"]}}
' '
# Exact match # Exact match
@ -178,7 +178,8 @@ new "restconf delete interfaces"
expecteq $(curl -s -X DELETE http://localhost/restconf/data/ietf-interfaces:interfaces) "" expecteq $(curl -s -X DELETE http://localhost/restconf/data/ietf-interfaces:interfaces) ""
new "restconf Check empty config" new "restconf Check empty config"
expectfn "curl -sG http://localhost/restconf/data/clixon-example:state" 0 "$state" expectfn "curl -sG http://localhost/restconf/data/clixon-example:state" 0 "$state
"
# XXX: gives <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"> # XXX: gives <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
# <interface xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"> # <interface xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
@ -192,7 +193,7 @@ expecteq "$(curl -s -G http://localhost/restconf/data/ietf-interfaces:interfaces
' '
new "restconf Check eth/0/0 added state" new "restconf Check eth/0/0 added state"
expecteq "$(curl -s -G http://localhost/restconf/data/clixon-example:state)" '{"clixon-example:state": {"op": "42"}} expecteq "$(curl -s -G http://localhost/restconf/data/clixon-example:state)" '{"clixon-example:state": {"op": ["42","41","43"]}}
' '
new "restconf Re-post eth/0/0 which should generate error" new "restconf Re-post eth/0/0 which should generate error"