From 69ff0e38914f9c4e6ce6b80494b297e1792dac4b Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Mon, 1 May 2017 12:46:09 +0200 Subject: [PATCH] Refined netconf none semantics in tests and text datastore --- CHANGELOG.txt | 2 + README.md | 15 ++++- apps/backend/backend_client.c | 1 - apps/restconf/{README => README.md} | 4 +- apps/restconf/restconf_methods.c | 9 +-- datastore/keyvalue/clixon_keyvalue.c | 4 +- datastore/text/clixon_xmldb_text.c | 88 ++++++++++++++++++++++++---- example/routing.conf.local | 6 +- lib/clixon/clixon_xml.h | 2 + lib/clixon/clixon_xml_db.h | 2 +- lib/clixon/clixon_xml_map.h | 2 +- lib/src/clixon_xml.c | 9 +++ lib/src/clixon_xml_db.c | 7 ++- lib/src/clixon_xml_map.c | 23 +++++--- lib/src/clixon_xsl.c | 17 +++--- test/test1.sh | 2 + test/test2.sh | 48 ++++++++++----- test/test3.sh | 38 +++++++----- test/test5.sh | 59 ++++++++++++++----- 19 files changed, 247 insertions(+), 91 deletions(-) rename apps/restconf/{README => README.md} (92%) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 993727db..ce6aadd4 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -29,6 +29,8 @@ # # ***** END LICENSE BLOCK ***** +- Refined netconf "none" semantics in tests and text datastore + - Moved apps/dbctrl to datastore/ - Added connect/disconnect/getopt/setopt and handle to xmldb API diff --git a/README.md b/README.md index 28c148b6..47347b22 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -CLIXON -====== +# CLIXON CLIXON is an automatic configuration manager where you from a YANG specification generate interactive CLI, NETCONF, RESTCONF and embedded @@ -12,6 +11,8 @@ applications such as CLICON/ROST does not run on CLIXON. Presentations and tutorial is found on the [CLICON project page](http://www.clicon.org) +## Installation + A typical installation is as follows: > configure # Configure clixon to platform @@ -22,17 +23,27 @@ A typical installation is as follows: One example applications is provided, the IETF IP YANG datamodel with generated CLI and configuration interface. It all origins from work at [KTH](http://www.csc.kth.se/~olofh/10G_OSR) +## Dependencies + [CLIgen](http://www.cligen.se) is required for building CLIXON. If you need to build and install CLIgen: git clone https://github.com/olofhagsand/cligen.git cd cligen; configure; make; make install +## Licenses + CLIXON is dual license. Either Apache License, Version 2.0 or GNU General Public License Version 2. You choose. See LICENSE.md for license, CHANGELOG for recent changes. +## Client code + +[CLI](apps/restconf). +[Restconf](apps/restconf). +[Netconf](apps/netconf). +[Netconf](apps/netconf). diff --git a/apps/backend/backend_client.c b/apps/backend/backend_client.c index 591d0e33..f5e26f8d 100644 --- a/apps/backend/backend_client.c +++ b/apps/backend/backend_client.c @@ -307,7 +307,6 @@ from_client_edit_config(clicon_handle h, } } if ((xc = xpath_first(xn, "config")) != NULL){ - /* XXX see from_client_xmlput() */ if (xmldb_put(h, target, operation, api_path, xc) < 0){ cprintf(cbret, "" "operation-failed" diff --git a/apps/restconf/README b/apps/restconf/README.md similarity index 92% rename from apps/restconf/README rename to apps/restconf/README.md index 8d750288..d058225b 100644 --- a/apps/restconf/README +++ b/apps/restconf/README.md @@ -66,8 +66,8 @@ curl -sX POST -d '{"clicon":{"interfaces":{"interface":{"name":"eth1","type":"et 3. DEBUGGING ++++++++++++ -Start the restconf programs with debug flag: -sudo su -c "/www-data/clixon_restconf -D" -s /bin/sh www-data +Start the restconf fastcgi program with debug flag: +sudo su -c "/www-data/clixon_restconf -Df /usr/local/etc/routing.conf" -s /bin/sh www-data Look at syslog: tail -f /var/log/syslog | grep clixon_restconf diff --git a/apps/restconf/restconf_methods.c b/apps/restconf/restconf_methods.c index b96b72b6..3194c4d6 100644 --- a/apps/restconf/restconf_methods.c +++ b/apps/restconf/restconf_methods.c @@ -296,7 +296,7 @@ api_data_edit(clicon_handle h, goto done; } cprintf(cbx, ""); - clicon_debug(1, "%s cbx: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path); + clicon_debug(1, "%s xml: %s api_path:%s",__FUNCTION__, cbuf_get(cbx), api_path); if (clicon_rpc_edit_config(h, "candidate", operation, api_path, @@ -337,7 +337,8 @@ api_data_edit(clicon_handle h, If the data resource already exists, then the POST request MUST fail and a "409 Conflict" status-line MUST be returned. - * Netconf: (nc:operation="create") | invoke an RPC operation + * Netconf: (nc:operation="create") | invoke an RPC operation * @example + */ int api_data_post(clicon_handle h, @@ -359,8 +360,8 @@ api_data_post(clicon_handle h, * @param[in] pi Offset, where to start pcvec * @param[in] qvec Vector of query string (QUERY_STRING) * @param[in] data Stream input data - * Example: - curl -X PUT -d {\"enabled\":\"false\"} http://127.0.0.1/restconf/data/interfaces/interface=eth1 + * @example + curl -X PUT -d '{"enabled":"false"}' http://127.0.0.1/restconf/data/interfaces/interface=eth1 * PUT: if the PUT request creates a new resource, diff --git a/datastore/keyvalue/clixon_keyvalue.c b/datastore/keyvalue/clixon_keyvalue.c index 1b4d3dc8..46e9f0b0 100644 --- a/datastore/keyvalue/clixon_keyvalue.c +++ b/datastore/keyvalue/clixon_keyvalue.c @@ -652,7 +652,7 @@ kv_get(xmldb_handle xh, } /* Top is special case */ if (!xml_flag(xt, XML_FLAG_MARK)) - if (xml_tree_prune_unmarked(xt, NULL) < 0) + if (xml_tree_prune_flagged(xt, XML_FLAG_MARK, 1, NULL) < 0) goto done; if (xml_apply(xt, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset, (void*)XML_FLAG_MARK) < 0) goto done; @@ -1309,7 +1309,7 @@ kv_put(xmldb_handle xh, yang_spec *yspec; char *dbfilename = NULL; - if ((xml_child_nr(xt)==0 || xml_body(xt)!= NULL) && + if (xt && (xml_child_nr(xt)==0 || xml_body(xt)!= NULL) && api_path && strlen(api_path) && strcmp(api_path,"/")) return xmldb_put_xkey(kh, db, op, api_path, xml_body(xt)); if ((yspec = kh->kh_yangspec) == NULL){ diff --git a/datastore/text/clixon_xmldb_text.c b/datastore/text/clixon_xmldb_text.c index 3710d96b..3de5bd2e 100644 --- a/datastore/text/clixon_xmldb_text.c +++ b/datastore/text/clixon_xmldb_text.c @@ -245,6 +245,32 @@ text_setopt(xmldb_handle xh, return retval; } +/*! Populate with spec + * @param[in] xt XML tree with some node marked + */ +int +xml_spec_populate(cxobj *x, + void *arg) +{ + int retval = -1; + yang_spec *yspec = (yang_spec*)arg; + char *name; + yang_stmt *y; /* yang node */ + cxobj *xp; /* xml parent */ + yang_stmt *yp; /* parent yang */ + + name = xml_name(x); + if ((xp = xml_parent(x)) != NULL && + (yp = xml_spec(xp)) != NULL) + y = yang_find_syntax((yang_node*)yp, xml_name(x)); + else + y = yang_find_topnode(yspec, name); /* still NULL for config */ + xml_spec_set(x, y); + retval = 0; + // done: + return retval; +} + /*! Get content of database using xpath. return a set of matching sub-trees * The function returns a minimal tree that includes all sub-trees that match * xpath. @@ -335,20 +361,20 @@ text_get(xmldb_handle xh, } /* Top is special case */ if (!xml_flag(xt, XML_FLAG_MARK)) - if (xml_tree_prune_unmarked(xt, NULL) < 0) + if (xml_tree_prune_flagged(xt, XML_FLAG_MARK, 1, NULL) < 0) goto done; if (xml_apply(xt, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset, (void*)XML_FLAG_MARK) < 0) goto done; + if (xml_apply(xt, CX_ELMNT, xml_spec_populate, yspec) < 0) + goto done; + if (xml_apply(xt, CX_ELMNT, xml_default, NULL) < 0) + goto done; + /* XXX does not work for top-level */ + if (xml_apply(xt, CX_ELMNT, xml_order, NULL) < 0) + goto done; + if (xml_apply(xt, CX_ELMNT, xml_sanity, NULL) < 0) + goto done; - if (0){ /* No xml_spec(xt) */ - if (xml_apply(xt, CX_ELMNT, xml_default, NULL) < 0) - goto done; - /* XXX does not work for top-level */ - if (xml_apply(xt, CX_ELMNT, xml_order, NULL) < 0) - goto done; - if (xml_apply(xt, CX_ELMNT, xml_sanity, NULL) < 0) - goto done; - } if (debug>1) clicon_xml2file(stderr, xt, 0, 1); if (xvec0 && xlen0){ @@ -755,11 +781,14 @@ text_modify(cxobj *x0, goto done; } /* Fall thru */ + case OP_NONE: /* XXX */ case OP_MERGE: case OP_REPLACE: if (x0==NULL){ if ((x0 = xml_new_spec(name, x0p, y)) == NULL) goto done; + if (op==OP_NONE) + xml_flag_set(x0, XML_FLAG_NONE); /* Mark for potential deletion */ if (x1bstr){ /* empty type does not have body */ if ((x0b = xml_new("body", x0)) == NULL) goto done; @@ -767,12 +796,24 @@ text_modify(cxobj *x0, } } if (x1bstr){ - if ((x0b = xml_body_get(x0)) == NULL) - goto done; + if ((x0b = xml_body_get(x0)) == NULL){ + if ((x0b = xml_new("body", x0)) == NULL) + goto done; + xml_type_set(x0b, CX_BODY); + } if (xml_value_set(x0b, x1bstr) < 0) goto done; } break; + case OP_DELETE: + if (x0==NULL){ + clicon_err(OE_XML, 0, "Object to delete does not exist"); + goto done; + } + case OP_REMOVE: + if (x0) + xml_purge(x0); + break; default: break; } /* switch op */ @@ -799,11 +840,15 @@ text_modify(cxobj *x0, xml_purge(x0); x0 = NULL; } + case OP_NONE: /* XXX */ case OP_MERGE: if (x0==NULL){ if ((x0 = xml_new_spec(name, x0p, y)) == NULL) goto done; + if (op==OP_NONE) + xml_flag_set(x0, XML_FLAG_NONE); /* Mark for potential deletion */ } + /* Loop through children of the modification tree */ x1c = NULL; while ((x1c = xml_child_each(x1, x1c, CX_ELMNT)) != NULL) { @@ -823,6 +868,15 @@ text_modify(cxobj *x0, goto done; } break; + case OP_DELETE: + if (x0==NULL){ + clicon_err(OE_XML, 0, "Object to delete does not exist"); + goto done; + } + case OP_REMOVE: + if (x0) + xml_purge(x0); + break; default: break; } /* CONTAINER switch op */ @@ -857,7 +911,7 @@ text_modify(cxobj *x0, * @endcode */ int -text_put(xmldb_handle xh, +text_put(xmldb_handle xh, char *db, enum operation_type op, char *api_path, @@ -877,10 +931,12 @@ text_put(xmldb_handle xh, cxobj *xnew = NULL; yang_node *y = NULL; +#if 0 /* Just ignore */ if ((op==OP_DELETE || op==OP_REMOVE) && xmod){ clicon_err(OE_XML, 0, "xml tree should be NULL for REMOVE/DELETE"); goto done; } +#endif if (text_db2file(th, db, &dbfile) < 0) goto done; if (dbfile==NULL){ @@ -942,6 +998,12 @@ text_put(xmldb_handle xh, else if (text_modify(xbase, xbasep, xmod, op, (yang_node*)y, yspec) < 0) goto done; + /* Remove NONE nodes if all subs recursively are also NONE */ + if (xml_tree_prune_flagged(xt, XML_FLAG_NONE, 0, NULL) <0) + goto done; + if (xml_apply(xt, CX_ELMNT, (xml_applyfn_t*)xml_flag_reset, + (void*)XML_FLAG_NONE) < 0) + goto done; // output: /* Print out top-level xml tree after modification to file */ if ((cb = cbuf_new()) == NULL){ diff --git a/example/routing.conf.local b/example/routing.conf.local index 8d705aba..698e56f4 100644 --- a/example/routing.conf.local +++ b/example/routing.conf.local @@ -26,4 +26,8 @@ CLICON_CLI_GENMODEL_TYPE VARS CLICON_CLIGEN_CALLBACK_SINGLE_ARG 0 # Enabled uses "startup" configuration on boot -CLICON_USE_STARTUP_CONFIG 0 \ No newline at end of file +CLICON_USE_STARTUP_CONFIG 0 + +# XMLDB datastore plugin filename (see datastore/ and clixon_xml_db.[ch]) +CLICON_XMLDB_PLUGIN /usr/local/lib/xmldb/text.so +#CLICON_XMLDB_PLUGIN /usr/local/lib/xmldb/keyvalue.so diff --git a/lib/clixon/clixon_xml.h b/lib/clixon/clixon_xml.h index 43ab57d9..cf40ff39 100644 --- a/lib/clixon/clixon_xml.h +++ b/lib/clixon/clixon_xml.h @@ -67,6 +67,7 @@ typedef int (xml_applyfn_t)(cxobj *yn, void *arg); #define XML_FLAG_ADD 0x02 /* Node is added (commits) or parent added rec*/ #define XML_FLAG_DEL 0x04 /* Node is deleted (commits) or parent deleted rec */ #define XML_FLAG_CHANGE 0x08 /* Node is changed (commits) or child changed rec */ +#define XML_FLAG_NONE 0x10 /* Node is added as NONE */ /* * Prototypes @@ -102,6 +103,7 @@ int xml_childvec_set(cxobj *x, int len); cxobj *xml_new(char *name, cxobj *xn_parent); cxobj *xml_new_spec(char *name, cxobj *xn_parent, void *spec); void *xml_spec(cxobj *x); +void *xml_spec_set(cxobj *x, void *spec); cxobj *xml_find(cxobj *xn_parent, char *name); int xml_addsub(cxobj *xp, cxobj *xc); diff --git a/lib/clixon/clixon_xml_db.h b/lib/clixon/clixon_xml_db.h index eced86bf..6b814f46 100644 --- a/lib/clixon/clixon_xml_db.h +++ b/lib/clixon/clixon_xml_db.h @@ -106,7 +106,7 @@ typedef int (xmldb_delete_t)(xmldb_handle xh, char *db); /* Type of xmldb init function */ typedef int (xmldb_init_t)(xmldb_handle xh, char *db); -/* grideye agent plugin init struct for the api */ +/* plugin init struct for the api */ struct xmldb_api{ int xa_version; int xa_magic; diff --git a/lib/clixon/clixon_xml_map.h b/lib/clixon/clixon_xml_map.h index 1cabeff6..437ac46f 100644 --- a/lib/clixon/clixon_xml_map.h +++ b/lib/clixon/clixon_xml_map.h @@ -64,7 +64,7 @@ int xml_diff(yang_spec *yspec, cxobj *xt1, cxobj *xt2, int yang2xmlkeyfmt(yang_stmt *ys, int inclkey, char **xkfmt); int xmlkeyfmt2key(char *xkfmt, cvec *cvv, char **xk); int xmlkeyfmt2xpath(char *xkfmt, cvec *cvv, char **xk); -int xml_tree_prune_unmarked(cxobj *xt, int *upmark); +int xml_tree_prune_flagged(cxobj *xt, int flag, int test, int *upmark); int xml_default(cxobj *x, void *arg); int xml_order(cxobj *x, void *arg); int xml_sanity(cxobj *x, void *arg); diff --git a/lib/src/clixon_xml.c b/lib/src/clixon_xml.c index ce836af7..0b4d3835 100644 --- a/lib/src/clixon_xml.c +++ b/lib/src/clixon_xml.c @@ -521,12 +521,21 @@ xml_new_spec(char *name, return x; } + void * xml_spec(cxobj *x) { return x->x_spec; } +void * +xml_spec_set(cxobj *x, + void *spec) +{ + x->x_spec = spec; + return 0; +} + /*! Find an XML node matching name among a parent's children. * * Get first XML node directly under x_up in the xml hierarchy with diff --git a/lib/src/clixon_xml_db.c b/lib/src/clixon_xml_db.c index 0ebf7c8e..bbfc215f 100644 --- a/lib/src/clixon_xml_db.c +++ b/lib/src/clixon_xml_db.c @@ -63,6 +63,9 @@ #include "clixon_options.h" #include "clixon_xml_db.h" +/* Set to log get and put requests */ +#define DEBUG 0 + /*! Load an xmldb storage plugin according to filename * If init function fails (not found, wrong version, etc) print a log and dont * add it. @@ -350,7 +353,7 @@ xmldb_get(clicon_handle h, goto done; } retval = xa->xa_get_fn(xh, db, xpath, xtop, xvec, xlen); -#if 0 /* XXX DEBUG */ +#if DEBUG if (retval == 0) { cbuf *cb = cbuf_new(); clicon_xml2cbuf(cb, *xtop, 0, 0); @@ -407,7 +410,7 @@ xmldb_put(clicon_handle h, clicon_err(OE_DB, 0, "Not connected to datastore plugin"); goto done; } -#if 0 /* XXX DEBUG */ +#if DEBUG { cbuf *cb = cbuf_new(); if (xt) diff --git a/lib/src/clixon_xml_map.c b/lib/src/clixon_xml_map.c index c89cc4c6..719eddf1 100644 --- a/lib/src/clixon_xml_map.c +++ b/lib/src/clixon_xml_map.c @@ -1076,16 +1076,23 @@ xmlkeyfmt2xpath(char *xkfmt, return retval; } -/*! Prune everything that has not been marked +/*! Prune everything that does not pass test * @param[in] xt XML tree with some node marked + * @param[in] flag Which flag to test for + * @param[in] test 1: test that flag is set, 0: test that flag is not set * @param[out] upmark Set if a child (recursively) has marked set. - * The function removes all branches that does not contain a marked child - * XXX: maybe key leafs should not be purged if list is not purged? - * XXX: consider move to clicon_xml + * The function removes all branches that does not a child that pass the test + * Purge all nodes that dont have MARK flag set recursively. + * Save all nodes that is MARK:ed or have at least one (grand*)child that is MARKed + * @code + * xml_tree_prune_flagged(xt, XML_FLAG_MARK, 1, NULL); + * @endcode */ int -xml_tree_prune_unmarked(cxobj *xt, - int *upmark) +xml_tree_prune_flagged(cxobj *xt, + int flag, + int test, + int *upmark) { int retval = -1; int submark; @@ -1097,12 +1104,12 @@ xml_tree_prune_unmarked(cxobj *xt, x = NULL; xprev = x = NULL; while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) { - if (xml_flag(x, XML_FLAG_MARK)){ + if (xml_flag(x, flag) == test?flag:0){ mark++; xprev = x; continue; /* mark and stop here */ } - if (xml_tree_prune_unmarked(x, &submark) < 0) + if (xml_tree_prune_flagged(x, flag, test, &submark) < 0) goto done; if (submark) mark++; diff --git a/lib/src/clixon_xsl.c b/lib/src/clixon_xsl.c index 441d15a4..b16da920 100644 --- a/lib/src/clixon_xsl.c +++ b/lib/src/clixon_xsl.c @@ -358,6 +358,13 @@ xpath_parse(char *xpath, else if (strncmp(s,"descendant-or-self::", strlen("descendant-or-self::"))==0){ xpath_element_new(A_DESCENDANT_OR_SELF, s+strlen("descendant-or-self::"), &xpnext); } +#if 1 + else if (strncmp(s,"..", strlen(".."))==0) /* abbreviatedstep */ + xpath_element_new(A_PARENT, s+strlen(".."), &xpnext); +#else + else if (strncmp(s,"..", strlen(s))==0) /* abbreviatedstep */ + xpath_element_new(A_PARENT, NULL, &xpnext); +#endif #if 1 /* Problems with .[userid=1321] */ else if (strncmp(s,".", strlen("."))==0) xpath_element_new(A_SELF, s+strlen("."), &xpnext); @@ -368,13 +375,7 @@ xpath_parse(char *xpath, else if (strncmp(s,"self::", strlen("self::"))==0) xpath_element_new(A_SELF, s+strlen("self::"), &xpnext); -#if 1 - else if (strncmp(s,"..", strlen(".."))==0) /* abbreviatedstep */ - xpath_element_new(A_PARENT, s+strlen(".."), &xpnext); -#else - else if (strncmp(s,"..", strlen(s))==0) /* abbreviatedstep */ - xpath_element_new(A_PARENT, NULL, &xpnext); -#endif + else if (strncmp(s,"parent::", strlen("parent::"))==0) xpath_element_new(A_PARENT, s+strlen("parent::"), &xpnext); else if (strncmp(s,"ancestor::", strlen("ancestor::"))==0) @@ -1076,7 +1077,7 @@ int main(int argc, char **argv) { int i; - cxobj **xv; + cxobj **xv cxobj *x; cxobj *xn; size_t xlen = 0; diff --git a/test/test1.sh b/test/test1.sh index 24d30a9f..b75e8434 100755 --- a/test/test1.sh +++ b/test/test1.sh @@ -26,6 +26,8 @@ sudo clixon_backend -If $clixon_cf if [ $? -ne 0 ]; then err fi +new "cli tests" + new "cli configure top" expectfn "$clixon_cli -1f $clixon_cf set interfaces" "" diff --git a/test/test2.sh b/test/test2.sh index 0267e87c..e6066427 100755 --- a/test/test2.sh +++ b/test/test2.sh @@ -20,14 +20,44 @@ sudo clixon_backend -If $clixon_cf if [ $? -ne 0 ]; then err fi + +new "netconf tests" + new "netconf get empty config" -expecteof "$clixon_netconf -qf $clixon_cf" "]]>]]>" "^]]>]]>$" +expecteof "$clixon_netconf -qf $clixon_cf" ']]>]]>' '^]]>]]>$' + +new "Add subtree eth0 using none which should not change anything" +expecteof "$clixon_netconf -qf $clixon_cf" "noneeth0]]>]]>" "^]]>]]>$" + +new "Check nothing added" +expecteof "$clixon_netconf -qf $clixon_cf" ']]>]]>' '^]]>]]>$' + +new "Add subtree eth0 using none and create which should add eth0" +expecteof "$clixon_netconf -qf $clixon_cf" 'eth0ethnone ]]>]]>' "^]]>]]>$" + +new "Check eth0 added using xpath" +expecteof "$clixon_netconf -qf $clixon_cf" ']]>]]>' "^eth0ethtrue]]>]]>$" + +new "Re-create same eth0 which should generate error" +expecteof "$clixon_netconf -qf $clixon_cf" 'eth0ethnone ]]>]]>' "^" + +new "Delete eth0 using none config" +expecteof "$clixon_netconf -qf $clixon_cf" 'eth0ethnone ]]>]]>' "^]]>]]>$" + +new "Check deleted eth0" +expecteof "$clixon_netconf -qf $clixon_cf" ']]>]]>' '^]]>]]>$' + +new "Re-Delete eth0 using none should generate error" +expecteof "$clixon_netconf -qf $clixon_cf" 'eth0ethnone ]]>]]>' "^" new "netconf edit config" expecteof "$clixon_netconf -qf $clixon_cf" "eth0eth1true
9.2.3.424
]]>]]>" "^]]>]]>$" new "netconf get config xpath" -expecteof "$clixon_netconf -qf $clixon_cf" "]]>]]>" "^true]]>]]>$" +expecteof "$clixon_netconf -qf $clixon_cf" ']]>]]>' "^true]]>]]>$" + +new "netconf get config xpath parent" +expecteof "$clixon_netconf -qf $clixon_cf" ']]>]]>' "^eth0trueeth1truetruefalse
9.2.3.424
]]>]]>$" new "netconf validate missing type" expecteof "$clixon_netconf -qf $clixon_cf" "]]>]]>" "^" @@ -48,23 +78,11 @@ new "netconf commit" expecteof "$clixon_netconf -qf $clixon_cf" "]]>]]>" "^]]>]]>$" new "netconf edit config replace" -expecteof "$clixon_netconf -qf $clixon_cf" "eth2ethmerge ]]>]]>" "^]]>]]>$" +expecteof "$clixon_netconf -qf $clixon_cf" "eth2ethmerge]]>]]>" "^]]>]]>$" new "netconf get replaced config" expecteof "$clixon_netconf -qf $clixon_cf" "]]>]]>" "^eth1ethtrueeth2ethtrue]]>]]>$" -new "netconf edit config create" -expecteof "$clixon_netconf -qf $clixon_cf" 'eth3ethnone ]]>]]>' "^]]>]]>$" - -new "netconf edit config create 2nd" -expecteof "$clixon_netconf -qf $clixon_cf" 'eth3ethmerge ]]>]]>' "^" - -new "netconf edit config delete" -expecteof "$clixon_netconf -qf $clixon_cf" 'eth3ethnone ]]>]]>' "^]]>]]>$" - -new "netconf get delete config" -expecteof "$clixon_netconf -qf $clixon_cf" "]]>]]>" "^eth1ethtrueeth2ethtrue]]>]]>$" - new "netconf discard-changes" expecteof "$clixon_netconf -qf $clixon_cf" "]]>]]>" "^]]>]]>$" diff --git a/test/test3.sh b/test/test3.sh index 0c04bdc6..ed1335e7 100755 --- a/test/test3.sh +++ b/test/test3.sh @@ -24,32 +24,40 @@ sudo start-stop-daemon -S -q -o -b -x /www-data/clixon_restconf -d /www-data -c sleep 1 +new "restconf tests" + new "restconf options" expectfn "curl -i -s -X OPTIONS http://localhost/restconf/data" "Allow: OPTIONS,HEAD,GET,POST,PUT,DELETE" -new "restconf get empty config" -expectfn "curl -sG http://localhost/restconf/data" "^null $" - -new "restconf put config" -expectfn 'curl -sX POST -d {"interfaces":{"interface":[{"name":"eth1","type":"eth","enabled":"true"},{"name":"eth0","type":"eth","enabled":"true"}]}} http://localhost/restconf/data' "" - -new "restconf get config" -expectfn "curl -sG http://localhost/restconf/data" '{"interfaces": {"interface": \[{"name": "eth1","type": "eth","enabled": "true"},{ "name": "eth0","type": "eth","enabled": "true"}\]}} -$' - new "restconf head" expectfn "curl -s -I http://localhost/restconf/data" "Content-Type: application/yang.data\+json" -new "restconf POST config" -expectfn 'curl -sX POST -d {"type":"eth"} http://localhost/restconf/data/interfaces/interface=eth4' "" +new "restconf get empty config" +expectfn "curl -sG http://localhost/restconf/data" "^null $" -new "restconf DELETE config" +# +new "Add subtree eth0,eth1 using POST" +expectfn 'curl -sX POST -d {"interfaces":{"interface":[{"name":"eth0","type":"eth","enabled":"true"},{"name":"eth1","type":"eth","enabled":"true"}]}} http://localhost/restconf/data' "" + +new "Check eth0 added" +expectfn "curl -sG http://localhost/restconf/data" '{"interfaces": {"interface": \[{"name": "eth0","type": "eth","enabled": "true"},{ "name": "eth1","type": "eth","enabled": "true"}\]}} +$' + +new "Re-post eth0 which should generate error" +expectfn 'curl -sX POST -d {"interfaces":{"interface":{"name":"eth0","type":"eth","enabled":"true"}}} http://localhost/restconf/data' "Not Found" + +new "delete eth0" expectfn 'curl -sX DELETE http://localhost/restconf/data/interfaces/interface=eth0' "" -new "restconf get config" -expectfn "curl -sG http://localhost/restconf/data" '{"interfaces": {"interface": \[{"name": "eth1","type": "eth","enabled": "true"},{ "name": "eth4","type": "eth","enabled": "true"}\]}} +new "Check deleted eth0" +expectfn 'curl -sG http://localhost/restconf/data' '{"interfaces": {"interface": {"name": "eth1","type": "eth","enabled": "true"}}} $' +new "Re-Delete eth0 using none should generate error" +expectfn 'curl -sX DELETE http://localhost/restconf/data/interfaces/interface=eth0' "Not Found" + +return + new "restconf PATCH config" expectfn 'curl -sX PATCH -d {"type":"eth"} http://localhost/restconf/data/interfaces/interface=eth4' "" diff --git a/test/test5.sh b/test/test5.sh index 11c85521..657ddc50 100755 --- a/test/test5.sh +++ b/test/test5.sh @@ -47,15 +47,18 @@ db='12first-entry13se run(){ name=$1 dir=/tmp/$name + if [ ! -d $dir ]; then mkdir $dir fi rm -rf $dir/* + conf="-d candidate -b $dir -p ../datastore/$name/$name.so -y /tmp -m ietf-ip" - echo "conf:$conf" +# echo "conf:$conf" new "datastore $name init" expectfn "$datastore $conf init" "" + # Whole tree operations new "datastore $name put all replace" expectfn "$datastore $conf put replace / $db" "" @@ -89,31 +92,55 @@ run(){ new "datastore $name put top create" expectfn "$datastore $conf put create / " "" # error -return + # Single key operations + # leaf + new "datastore $name put all delete" + expectfn "$datastore $conf delete" "" + new "datastore $name init" + expectfn "$datastore $conf init" "" + new "datastore $name create leaf" + expectfn "$datastore $conf put create /x/y=1,3/c newentry" - new "datastore $name put top" - expectfn "$datastore $conf put replace / $db" + new "datastore $name create leaf" + expectfn "$datastore $conf put create /x/y=1,3/c newentry" - new "datastore $name put del" + new "datastore $name delete leaf" + expectfn "$datastore $conf put delete /x/y=1,3" + + new "datastore $name replace leaf" + expectfn "$datastore $conf put create /x/y=1,3/c newentry" + + new "datastore $name remove leaf" + expectfn "$datastore $conf put remove /x/g" + + new "datastore $name remove leaf" + expectfn "$datastore $conf put remove /x/y=1,3/c" + + new "datastore $name delete leaf" expectfn "$datastore $conf put delete /x/g" -return - new "datastore $name get empty" - expectfn "$datastore $conf get /" "^$" + new "datastore $name merge leaf" + expectfn "$datastore $conf put merge /x/g nalle" - new "datastore $name put top" - expectfn "$datastore $conf put replace / foobarfie" "" + new "datastore $name replace leaf" + expectfn "$datastore $conf put replace /x/g nalle" - new "datastore $name get config" - expectfn "$datastore $conf get /" "^foobarfie$" + new "datastore $name merge leaf" + expectfn "$datastore $conf put merge /x/y=1,3/c newentry" - new "datastore $name put delete" - expectfn "$datastore $conf put delete / " "" + new "datastore $name replace leaf" + expectfn "$datastore $conf put replace /x/y=1,3/c newentry" - new "datastore $name get deleted" - expectfn "$datastore $conf get /" "^$" + new "datastore $name create leaf" + expectfn "$datastore $conf put create /x/h aaa" + + new "datastore $name create leaf" + expectfn "$datastore $conf put create /x/y=1,3/c newentry" + +#leaf-list + rm -rf $dir }