#!/usr/bin/env bash # Yang features. if-feature. # The test has a example module with FEATURES A and B, where A is enabled and # B is disabled. # It also uses an ietf-router module where (only) router-id is enabled # Also check modules-state (RFC7895) announces the enabled features. # # From RFC7950: # 7.20.1 Schema nodes tagged with an "if-feature" statement are _ignored_ by # the server unless the server supports the given feature expression. # 8.1: There MUST be no nodes tagged with "if-feature" present if the # "if-feature" expression evaluates to "false" in the server. # - Should the server just "ignore" these nodes or actively reject them? # # Clixon has a strict implementation of the features so that setting # data with disabled features is same as if they are not present in the Yang. # Which means no cli syntax or edit operations were syntactically allowed # (and therefore invalid). # 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/test.yang # Note ietf-routing@2018-03-13 assumed cat < $cfg $APPNAME:A $APPNAME:A1 ietf-routing:router-id $cfg /usr/local/share/clixon $IETFRFC $fyang /usr/local/lib/$APPNAME/clispec /usr/local/lib/$APPNAME/cli $APPNAME /usr/local/var/$APPNAME/$APPNAME.sock /usr/local/var/$APPNAME/$APPNAME.pidfile /usr/local/var/$APPNAME true EOF cat < $fyang module example{ yang-version 1.1; namespace "urn:example:clixon"; prefix ex; import ietf-routing { prefix rt; } feature A{ description "This test feature is enabled"; } feature A1{ description "This test feature is enabled (extra for multiple)"; } feature B{ description "This test feature is disabled"; } feature B1{ description "This test feature is disabled (extra for multiple)"; } leaf x{ if-feature A; type "string"; } leaf y{ if-feature B; type "string"; } leaf z{ type "string"; } leaf m1{ if-feature "A and A1"; description "Enabled"; type "string"; } leaf m2{ if-feature "A or A1"; description "Enabled"; type "string"; } leaf m3{ if-feature "A and B"; description "Not enabled"; type "string"; } leaf m4{ if-feature "A or B"; description "Enabled"; type "string"; } leaf m5{ if-feature "B and B1"; description "Not enabled"; type "string"; } leaf m6{ if-feature "B or B1"; description "Not enabled"; type "string"; } leaf m7{ if-feature "A or A1 or B or B1"; description "Enabled"; type "string"; } leaf m8{ if-feature "A and A1 and B and B1"; description "Not enabled"; type "string"; } } EOF # Run netconf feature test # 1: syntax node # 2: disabled or enabled function testrun() { node=$1 enabled=$2 if $enabled; then new "netconf set $node" expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<$node xmlns=\"urn:example:clixon\">foo]]>]]>" "^]]>]]>$" new "netconf validate $node" expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO]]>]]>" "^]]>]]>$" else new "netconf set $node, expect fail" expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<$node xmlns=\"urn:example:clixon\">foo]]>]]>" "^applicationunknown-element$nodeerrorFailed to find YANG spec of XML node: $node with parent: config in namespace: urn:example:clixon]]>]]>$" fi new "netconf discard-changes" expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO]]>]]>" "^]]>]]>$" } 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 new "waiting" wait_backend fi new "cli enabled feature" expectpart "$($clixon_cli -1f $cfg set x foo)" 0 "" new "cli disabled feature" expectpart "$($clixon_cli -1f $cfg -l o set y foo)" 255 "CLI syntax error: \"set y foo\": Unknown command" new "cli enabled feature in other module" expectpart "$($clixon_cli -1f $cfg set routing router-id 1.2.3.4)" 0 "" new "cli disabled feature in other module" expectpart "$($clixon_cli -1f $cfg -l o set routing ribs rib default-rib false)" 255 "CLI syntax error: \"set routing ribs rib default-rib false\": Unknown command" new "netconf discard-changes" expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO]]>]]>" "^]]>]]>$" # Single if-feature testrun x true testrun y false # Multiple if-feature testrun m1 true testrun m2 true testrun m3 false testrun m4 true testrun m5 false testrun m6 false testrun m7 true testrun m8 false # This test has been broken up into all different modules instead of one large # reply since the modules change so often new "netconf schema resource, RFC 7895" ret=$($clixon_netconf -qf $cfg<]]>]]> EOF ) #echo $ret new "netconf modules-state header" expect="^" match=`echo "$ret" | grep --null -Go "$expect"` if [ -z "$match" ]; then err "$expect" "$ret" fi new "netconf module A" expect="exampleurn:example:clixonAA1implement" match=`echo "$ret" | grep --null -Go "$expect"` if [ -z "$match" ]; then err "$expect" "$ret" fi if false ; then # clixon "config" is a meta-config and not visisble in regular features new "netconf module clixon-config" expect="clixon-config2018-09-30" match=`echo "$ret" | grep --null -Go "$expect"` if [ -z "$match" ]; then err "$expect" "$ret" fi fi # false new "netconf module ietf-inet-types" expect="ietf-inet-types2020-07-06urn:ietf:params:xml:ns:yang:ietf-inet-typesimplement" match=`echo "$ret" | grep --null -Go "$expect"` if [ -z "$match" ]; then err "$expect" "$ret" fi new "netconf module ietf-interfaces" expect="ietf-interfaces2018-02-20urn:ietf:params:xml:ns:yang:ietf-interfacesimplement" match=`echo "$ret" | grep --null -Go "$expect"` if [ -z "$match" ]; then err "$expect" "$ret" fi # Note order of features in ietf-netconf yang is alphabetically: candidate, startup, validate, xpath new "netconf module ietf-netconf" expect="ietf-netconf2011-06-01urn:ietf:params:xml:ns:netconf:base:1.0candidatevalidatexpathimplement" match=`echo "$ret" | grep --null -Go "$expect"` if [ -z "$match" ]; then err "$expect" "$ret" fi new "netconf module ietf-routing" expect="ietf-routing2018-03-13urn:ietf:params:xml:ns:yang:ietf-routingrouter-idimplement" match=`echo "$ret" | grep --null -Go "$expect"` if [ -z "$match" ]; then err "$expect" "$ret" fi expect="ietf-yang-library2019-01-04urn:ietf:params:xml:ns:yang:ietf-yang-libraryimplement" match=`echo "$ret" | grep --null -Go "$expect"` if [ -z "$match" ]; then err "$expect" "$ret" fi new "netconf module ietf-yang_types" expect="ietf-yang-types2013-07-15urn:ietf:params:xml:ns:yang:ietf-yang-typesimplement" match=`echo "$ret" | grep --null -Go "$expect"` if [ -z "$match" ]; then err "$expect" "$ret" fi 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 #------------------------ # Negative test, if if-feature but no feature, signal error cat < $fyang module example{ yang-version 1.1; namespace "urn:example:clixon"; prefix ex; feature A{ description "This feature exists"; } leaf x{ if-feature "A or B"; type "string"; } } EOF 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: feature missing expected fail" expectpart "$(sudo $clixon_backend -F1s init -f $cfg -l o)" 255 " Yang module example has IF_FEATURE B, but no such FEATURE statement exists" stop_backend -f $cfg fi unset ret endtest rm -rf $dir