From fcf9a8b0b0de53aef4939eeca767521ef984db00 Mon Sep 17 00:00:00 2001 From: Olof Hagsand Date: Mon, 13 Feb 2023 20:21:44 +0100 Subject: [PATCH] C-API: Exposed diff function Test: double leaf validate test --- apps/cli/cli_common.c | 78 +--------------------------- lib/clixon/clixon_proto.h | 7 --- lib/clixon/clixon_xml.h | 9 ++++ lib/clixon/clixon_xml_map.h | 1 + lib/src/clixon_validate.c | 6 +-- lib/src/clixon_xml_map.c | 83 ++++++++++++++++++++++++++++++ lib/src/clixon_yang_schema_mount.c | 1 + test/test_netconf.sh | 19 ++++++- 8 files changed, 115 insertions(+), 89 deletions(-) diff --git a/apps/cli/cli_common.c b/apps/cli/cli_common.c index 1b4b781a..e0d1500c 100644 --- a/apps/cli/cli_common.c +++ b/apps/cli/cli_common.c @@ -733,82 +733,6 @@ cli_validate(clicon_handle h, return retval; } -/*! Compare two dbs using XML. Write to file and run diff - */ -static int -compare_xmls(cxobj *xc1, - cxobj *xc2, - enum format_enum format) -{ - int fd; - FILE *f; - char filename1[MAXPATHLEN]; - char filename2[MAXPATHLEN]; - int retval = -1; - cbuf *cb = NULL; - - snprintf(filename1, sizeof(filename1), "/tmp/cliconXXXXXX"); - snprintf(filename2, sizeof(filename2), "/tmp/cliconXXXXXX"); - if ((fd = mkstemp(filename1)) < 0){ - clicon_err(OE_UNDEF, errno, "tmpfile"); - goto done; - } - if ((f = fdopen(fd, "w")) == NULL) - goto done; - switch(format){ - case FORMAT_TEXT: - if (clixon_txt2file(f, xc1, 0, cligen_output, 1, 1) < 0) - goto done; - break; - case FORMAT_XML: - default: - if (clixon_xml2file(f, xc1, 0, 1, cligen_output, 1, 1) < 0) - goto done; - break; - } - fclose(f); - close(fd); - - if ((fd = mkstemp(filename2)) < 0){ - clicon_err(OE_UNDEF, errno, "mkstemp: %s", strerror(errno)); - goto done; - } - if ((f = fdopen(fd, "w")) == NULL) - goto done; - - switch(format){ - case FORMAT_TEXT: - if (clixon_txt2file(f, xc2, 0, cligen_output, 1, 1) < 0) - goto done; - break; - case FORMAT_XML: - default: - if (clixon_xml2file(f, xc2, 0, 1, cligen_output, 1, 1) < 0) - goto done; - break; - } - - fclose(f); - close(fd); - - if ((cb = cbuf_new()) == NULL){ - clicon_err(OE_CFG, errno, "cbuf_new"); - goto done; - } - cprintf(cb, "diff -dU 1 %s %s | grep -v @@ | sed 1,2d", - filename1, filename2); - if (system(cbuf_get(cb)) < 0) - goto done; - - retval = 0; - done: - if (cb) - cbuf_free(cb); - unlink(filename1); - unlink(filename2); - return retval; -} - /*! Compare two dbs using XML. Write to file and run diff * @param[in] h Clicon handle * @param[in] cvv @@ -845,7 +769,7 @@ compare_dbs(clicon_handle h, clixon_netconf_error(xerr, "Get configuration", NULL); goto done; } - if (compare_xmls(xc1, xc2, format) < 0) /* astext? */ + if (clixon_compare_xmls(xc1, xc2, format, cligen_output) < 0) /* astext? */ goto done; retval = 0; done: diff --git a/lib/clixon/clixon_proto.h b/lib/clixon/clixon_proto.h index 74f92f40..076b6021 100644 --- a/lib/clixon/clixon_proto.h +++ b/lib/clixon/clixon_proto.h @@ -43,13 +43,6 @@ /* * Types */ -enum format_enum{ - FORMAT_XML, - FORMAT_JSON, - FORMAT_TEXT, - FORMAT_CLI, - FORMAT_NETCONF -}; /* Protocol message header */ struct clicon_msg { diff --git a/lib/clixon/clixon_xml.h b/lib/clixon/clixon_xml.h index d70e2a02..a44060c8 100644 --- a/lib/clixon/clixon_xml.h +++ b/lib/clixon/clixon_xml.h @@ -177,6 +177,15 @@ typedef int (xml_applyfn_t)(cxobj *x, void *arg); typedef struct clixon_xml_vec clixon_xvec; /* struct defined in clicon_xml_vec.c */ +/* Alternative formats */ +enum format_enum{ + FORMAT_XML, + FORMAT_JSON, + FORMAT_TEXT, + FORMAT_CLI, + FORMAT_NETCONF +}; + /* * xml_flag() flags: */ diff --git a/lib/clixon/clixon_xml_map.h b/lib/clixon/clixon_xml_map.h index af6b3dbb..6beda9ce 100644 --- a/lib/clixon/clixon_xml_map.h +++ b/lib/clixon/clixon_xml_map.h @@ -75,5 +75,6 @@ int yang_xml_mandatory(cxobj *xt, yang_stmt *ys); int xml_rpc_isaction(cxobj *xn); int xml_find_action(cxobj *xn, int top, cxobj **xap); int purge_tagged_nodes(cxobj *xn, char *ns, char *name, char *value, int keepnode); +int clixon_compare_xmls(cxobj *xc1, cxobj *xc2, enum format_enum format, clicon_output_cb *fn); #endif /* _CLIXON_XML_MAP_H_ */ diff --git a/lib/src/clixon_validate.c b/lib/src/clixon_validate.c index 6dd21830..1af42b14 100644 --- a/lib/src/clixon_validate.c +++ b/lib/src/clixon_validate.c @@ -1101,7 +1101,7 @@ xml_yang_validate_list_key_only(cxobj *xt, int ret; cxobj *x; - /* if not given by argument (overide) use default link + /* if not given by argument (override) use default link and !Node has a config sub-statement and it is false */ if ((yt = xml_spec(xt)) != NULL && yang_config(yt) != 0 && @@ -1229,8 +1229,8 @@ xml_yang_validate_all(clicon_handle h, /* Do not validate beyond mountpoints */ if ((ret = xml_yang_mount_get(xt, NULL)) < 0) goto done; - if (ret == 1) - goto ok; + if (ret == 1) + goto ok; /* Actually this may be somewhat too strict */ #endif /* if not given by argument (overide) use default link and !Node has a config sub-statement and it is false */ diff --git a/lib/src/clixon_xml_map.c b/lib/src/clixon_xml_map.c index 58b620dd..f2f9f1ab 100644 --- a/lib/src/clixon_xml_map.c +++ b/lib/src/clixon_xml_map.c @@ -77,6 +77,8 @@ #include "clixon_netconf_lib.h" #include "clixon_xml_sort.h" #include "clixon_yang_type.h" +#include "clixon_text_syntax.h" +#include "clixon_xml_io.h" #include "clixon_xml_map.h" /* Local types @@ -1703,3 +1705,84 @@ purge_tagged_nodes(cxobj *xn, return retval; } +/*! Compare two dbs using XML. Write to file and run diff + * + * @param[in] xc1 XML tree 1 + * @param[in] xc2 XML tree 2 + * @param[in] format "text"|"xml"|"json"|"cli"|"netconf" (see format_enum) + * @param[in] fn File print function (if NULL, use fprintf) + */ +int +clixon_compare_xmls(cxobj *xc1, + cxobj *xc2, + enum format_enum format, + clicon_output_cb *fn) +{ + int fd; + FILE *f; + char filename1[MAXPATHLEN]; + char filename2[MAXPATHLEN]; + int retval = -1; + cbuf *cb = NULL; + + snprintf(filename1, sizeof(filename1), "/tmp/cliconXXXXXX"); + snprintf(filename2, sizeof(filename2), "/tmp/cliconXXXXXX"); + if ((fd = mkstemp(filename1)) < 0){ + clicon_err(OE_UNDEF, errno, "tmpfile"); + goto done; + } + if ((f = fdopen(fd, "w")) == NULL) + goto done; + switch(format){ + case FORMAT_TEXT: + if (clixon_txt2file(f, xc1, 0, cligen_output, 1, 1) < 0) + goto done; + break; + case FORMAT_XML: + default: + if (clixon_xml2file(f, xc1, 0, 1, cligen_output, 1, 1) < 0) + goto done; + break; + } + fclose(f); + close(fd); + + if ((fd = mkstemp(filename2)) < 0){ + clicon_err(OE_UNDEF, errno, "mkstemp: %s", strerror(errno)); + goto done; + } + if ((f = fdopen(fd, "w")) == NULL) + goto done; + + switch(format){ + case FORMAT_TEXT: + if (clixon_txt2file(f, xc2, 0, cligen_output, 1, 1) < 0) + goto done; + break; + case FORMAT_XML: + default: + if (clixon_xml2file(f, xc2, 0, 1, cligen_output, 1, 1) < 0) + goto done; + break; + } + + fclose(f); + close(fd); + + if ((cb = cbuf_new()) == NULL){ + clicon_err(OE_CFG, errno, "cbuf_new"); + goto done; + } + cprintf(cb, "diff -dU 1 %s %s | grep -v @@ | sed 1,2d", + filename1, filename2); + if (system(cbuf_get(cb)) < 0) + goto done; + + retval = 0; + done: + if (cb) + cbuf_free(cb); + unlink(filename1); + unlink(filename2); + return retval; +} diff --git a/lib/src/clixon_yang_schema_mount.c b/lib/src/clixon_yang_schema_mount.c index adb1b09e..0f2ecad0 100644 --- a/lib/src/clixon_yang_schema_mount.c +++ b/lib/src/clixon_yang_schema_mount.c @@ -162,6 +162,7 @@ xml_yang_mount_get(cxobj *xt, goto ok; if (xml2xpath(xt, NULL, 1, &xpath) < 0) goto done; + /* Special value in yang unknown node for mount-points: mapping from xpath->mounted yspec */ if ((cvv = yang_cvec_get(yu)) == NULL) goto ok; if ((cv = cvec_find(cvv, xpath)) == NULL) diff --git a/test/test_netconf.sh b/test/test_netconf.sh index dc4de610..8687961b 100755 --- a/test/test_netconf.sh +++ b/test/test_netconf.sh @@ -62,6 +62,9 @@ module clixon-example{ leaf name{ type string; } + leaf value{ + type string; + } } } /* State data (not config) for the example application*/ @@ -223,7 +226,7 @@ new "Re-Delete eth/0/0 using none should generate error" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "eth/0/0ex:ethnone " "" "" new "Add interface without key" -expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "ex:ethnone " "" "applicationmissing-elementnameerrorMandatory key in 'list interface' in ietf-interfaces.yang:107" +expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "ex:ethnone " "applicationmissing-elementnameerrorMandatory key in 'list interface' in ietf-interfaces.yang:[0-9]\+" "" new "netconf discard-changes" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" @@ -430,10 +433,22 @@ expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" " new "netconf client-side rpc" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "val42" "" "val42" +# Negative tests new "netconf extra leaf in leaf should fail" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "e0e1" "" "applicationunknown-elementnameerrorFailed to find YANG spec of XML node: name with parent: name in namespace: urn:ietf:params:xml:ns:yang:ietf-interfaces" -# Negative tests +new "netconf duplicate keys" +expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "xxyy
" "" "" + +new "netconf validate duplicate keys expect fail" +expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "protocoloperation-failedtoo-many-elements" "" + +new "netconf duplicate values" +expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "xxfoobar
" "" "" + +new "netconf validate duplicate values expect fail" +expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "protocoloperation-failedtoo-many-elements" "" + new "netconf xpath syntax error (api-path not xpath) should fail" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "applicationoperation-failederrorxpath parser on line 1: syntax error at or before: ','"