Empty leaf values, eg <a></a> are now checked at vlidation.

This commit is contained in:
Olof hagsand 2019-04-10 17:35:36 +02:00
parent 4a1e0f2cbc
commit 881dd56ee1
5 changed files with 56 additions and 20 deletions

View file

@ -92,6 +92,9 @@
``` ```
### Minor changes ### Minor changes
* Empty leaf values, eg <a></a> are now checked at vlidation.
* Empty values were skipped in validation.
* They are now checked and invalid for ints, dec64, etc, but are treated as empty string "" for string types.
* Optimized validation by making xml_diff work on raw cache tree (not copies) * Optimized validation by making xml_diff work on raw cache tree (not copies)
* Added syntactic check for yang status: current, deprecated or obsolete. * Added syntactic check for yang status: current, deprecated or obsolete.
* Added `xml_wrap` function that adds an XML node above a node as a wrapper * Added `xml_wrap` function that adds an XML node above a node as a wrapper

View file

@ -663,6 +663,7 @@ xml_yang_validate_add(cxobj *xt,
char *body; char *body;
int ret; int ret;
cxobj *x; cxobj *x;
enum cv_type cvtype;
/* if not given by argument (overide) use default link /* if not given by argument (overide) use default link
and !Node has a config sub-statement and it is false */ and !Node has a config sub-statement and it is false */
@ -688,18 +689,29 @@ xml_yang_validate_add(cxobj *xt,
/* In the union case, value is parsed as generic REST type, /* In the union case, value is parsed as generic REST type,
* needs to be reparsed when concrete type is selected * needs to be reparsed when concrete type is selected
*/ */
if ((body = xml_body(xt)) != NULL){ if ((body = xml_body(xt)) == NULL){
/* We do not allow ints to be empty. Otherwise NULL strings
* are considered as "" */
cvtype = cv_type_get(cv);
if (cv_isint(cvtype) || cvtype == CGV_BOOL || cvtype == CGV_DEC64){
if (netconf_bad_element(cbret, "application", yt->ys_argument, "Invalid NULL value") < 0)
goto done;
goto fail;
}
}
else{
if (cv_parse1(body, cv, &reason) != 1){ if (cv_parse1(body, cv, &reason) != 1){
if (netconf_bad_element(cbret, "application", yt->ys_argument, reason) < 0) if (netconf_bad_element(cbret, "application", yt->ys_argument, reason) < 0)
goto done; goto done;
goto fail; goto fail;
} }
}
if ((ys_cv_validate(cv, yt, &reason)) != 1){ if ((ys_cv_validate(cv, yt, &reason)) != 1){
if (netconf_bad_element(cbret, "application", yt->ys_argument, reason) < 0) if (netconf_bad_element(cbret, "application", yt->ys_argument, reason) < 0)
goto done; goto done;
goto fail; goto fail;
} }
}
break; break;
default: default:
break; break;

View file

@ -364,7 +364,7 @@ cv_validate1(cg_var *cv,
cg_var *cv2; cg_var *cv2;
int retval2; int retval2;
yang_stmt *yi = NULL; yang_stmt *yi = NULL;
char *str; char *str = NULL;
int found; int found;
char **vec = NULL; char **vec = NULL;
int nvec; int nvec;
@ -435,7 +435,8 @@ cv_validate1(cg_var *cv,
case CGV_STRING: case CGV_STRING:
case CGV_REST: case CGV_REST:
if ((str = cv_string_get(cv)) == NULL) if ((str = cv_string_get(cv)) == NULL)
break; uu = 0; /* equal no string with empty string for range check */
else
uu = strlen(str); uu = strlen(str);
rets = range_check(uu, cv1, cv2, uint64); rets = range_check(uu, cv1, cv2, uint64);
break; break;
@ -470,10 +471,13 @@ cv_validate1(cg_var *cv,
case CGV_STRING: case CGV_STRING:
case CGV_REST: case CGV_REST:
str = cv_string_get(cv); str = cv_string_get(cv);
/* Note, if there is no value, eg <s/>, str is NULL.
*/
if (restype){ if (restype){
if (strcmp(restype, "enumeration") == 0){ if (strcmp(restype, "enumeration") == 0){
found = 0; found = 0;
yi = NULL; yi = NULL;
if (str != NULL)
while ((yi = yn_each(yrestype, yi)) != NULL){ while ((yi = yn_each(yrestype, yi)) != NULL){
if (yi->ys_keyword != Y_ENUM) if (yi->ys_keyword != Y_ENUM)
continue; continue;
@ -488,11 +492,13 @@ cv_validate1(cg_var *cv,
goto fail; goto fail;
} }
} }
if (strcmp(restype, "bits") == 0){ if (strcmp(restype, "bits") == 0 && str != NULL){
/* The lexical representation of the bits type is a space-separated list /* The lexical representation of the bits type is a space-separated list
* of the names of the bits that are set. A zero-length string thus * of the names of the bits that are set. A zero-length string thus
* represents a value where no bits are set. * represents a value where no bits are set.
*/ */
nvec = 0;
if ((vec = clicon_strsep(str, " \t", &nvec)) == NULL) if ((vec = clicon_strsep(str, " \t", &nvec)) == NULL)
goto done; goto done;
for (i=0; i<nvec; i++){ for (i=0; i<nvec; i++){
@ -521,7 +527,7 @@ cv_validate1(cg_var *cv,
char *posix = NULL; char *posix = NULL;
if (regexp_xsd2posix(pattern, &posix) < 0) if (regexp_xsd2posix(pattern, &posix) < 0)
goto done; goto done;
if ((retval2 = match_regexp(str, posix)) < 0){ if ((retval2 = match_regexp(str?str:"", posix)) < 0){
clicon_err(OE_DB, 0, "match_regexp: %s", pattern); clicon_err(OE_DB, 0, "match_regexp: %s", pattern);
return -1; return -1;
} }
@ -536,8 +542,9 @@ cv_validate1(cg_var *cv,
} }
} }
break; break;
case CGV_ERR:
case CGV_VOID: case CGV_VOID:
break; /* empty type OK */
case CGV_ERR:
retval = 0; retval = 0;
if (reason) if (reason)
*reason = cligen_reason("Invalid cv"); *reason = cligen_reason("Invalid cv");

View file

@ -138,7 +138,7 @@ new "netconf EXAMPLE subscription"
expectwait "$clixon_netconf -qf $cfg -y $fyang" '<rpc><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"><stream>EXAMPLE</stream></create-subscription></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]><notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>20' $NCWAIT expectwait "$clixon_netconf -qf $cfg -y $fyang" '<rpc><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"><stream>EXAMPLE</stream></create-subscription></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]><notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>20' $NCWAIT
new "netconf subscription with empty startTime" new "netconf subscription with empty startTime"
expectwait "$clixon_netconf -qf $cfg -y $fyang" '<rpc><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"><stream>EXAMPLE</stream><startTime/></create-subscription></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]><notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>20' $NCWAIT expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"><stream>EXAMPLE</stream><startTime/></create-subscription></rpc>]]>]]>' '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>startTime</bad-element></error-info><error-severity>error</error-severity><error-message>regexp match fail:'
new "netconf EXAMPLE subscription with simple filter" new "netconf EXAMPLE subscription with simple filter"
expectwait "$clixon_netconf -qf $cfg -y $fyang" '<rpc><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"><stream>EXAMPLE</stream><filter type="xpath" select="event"/></create-subscription></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]><notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>20' $NCWAIT expectwait "$clixon_netconf -qf $cfg -y $fyang" '<rpc><create-subscription xmlns="urn:ietf:params:xml:ns:netmod:notification"><stream>EXAMPLE</stream><filter type="xpath" select="event"/></create-subscription></rpc>]]>]]>' '^<rpc-reply><ok/></rpc-reply>]]>]]><notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0"><eventTime>20' $NCWAIT

View file

@ -123,6 +123,9 @@ module example{
enum down; enum down;
} }
} }
leaf num0 {
type int32;
}
leaf num1 { leaf num1 {
type int32 { type int32 {
range "1"; range "1";
@ -315,6 +318,17 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><can
new "cli bits validate" new "cli bits validate"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang validate" 0 "^$" expectfn "$clixon_cli -1f $cfg -l o -y $fyang validate" 0 "^$"
#-------- num0 empty value
new "netconf num0 no value"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><num0 xmlns="urn:example:clixon"/></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf validate no value wrong"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>num0</bad-element></error-info><error-severity>error</error-severity><error-message>Invalid NULL value</error-message></rpc-error></rpc-reply>]]>]]>'
new "netconf discard-changes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
#-------- num1 single range (1) #-------- num1 single range (1)
new "cli range test num1 1 OK" new "cli range test num1 1 OK"