#!/usr/bin/env bash # RPC tests # Validate parameters in restconf and netconf, check namespaces, etc # See rfc8040 3.6 # Use the example application that has one mandatory input arg, # At the end is an alternative Yang without mandatory arg for # valid empty input and output. # 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.xml # Define default restconfig config: RESTCONFIG RESTCONFIG=$(restconf_config none false) # Use yang in example cat < $cfg $cfg clixon-restconf:allow-auth-none /usr/local/share/clixon $IETFRFC clixon-example /usr/local/lib/$APPNAME/backend /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 $RESTCONFIG 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" start_backend -s init -f $cfg fi new "waiting" wait_backend if [ $RC -ne 0 ]; then new "kill old restconf daemon" stop_restconf_pre new "start restconf daemon" start_restconf -f $cfg new "waiting" wait_restconf fi new "rpc tests" # 1.First some positive tests vary media types # extra complex because pattern matching on return haders new "restconf empty rpc" ret=$(curl $CURLOPTS -X POST $RCPROTO://localhost/restconf/operations/clixon-example:empty) expect="204 No Content" match=`echo $ret | grep --null -Eo "$expect"` if [ -z "$match" ]; then err "$expect" "$ret" fi new "netconf empty rpc" expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO]]>]]>" "^]]>]]>$" new "restconf example rpc json/json default - no http media headers" expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":0}}' $RCPROTO://localhost/restconf/operations/clixon-example:example)" 0 'HTTP/1.1 200 OK' 'Content-Type: application/yang-data+json' '{"clixon-example:output":{"x":"0","y":"42"}}' new "restconf example rpc json/json change y default" expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":"0","y":"99"}}' $RCPROTO://localhost/restconf/operations/clixon-example:example)" 0 'Content-Type: application/yang-data+json' '{"clixon-example:output":{"x":"0","y":"99"}}' new "restconf example rpc json/json" # XXX example:input example:output expectpart "$(curl $CURLOPTS -X POST -H 'Content-Type: application/yang-data+json' -H 'Accept: application/yang-data+json' -d '{"clixon-example:input":{"x":"0"}}' $RCPROTO://localhost/restconf/operations/clixon-example:example)" 0 'Content-Type: application/yang-data+json' '{"clixon-example:output":{"x":"0","y":"42"}}' new "restconf example rpc xml/json" expectpart "$(curl $CURLOPTS -X POST -H 'Content-Type: application/yang-data+xml' -H 'Accept: application/yang-data+json' -d '0' $RCPROTO://localhost/restconf/operations/clixon-example:example)" 0 'Content-Type: application/yang-data+json' '{"clixon-example:output":{"x":"0","y":"42"}}' new "restconf example rpc json/xml" expectpart "$(curl $CURLOPTS -X POST -H 'Content-Type: application/yang-data+json' -H 'Accept: application/yang-data+xml' -d '{"clixon-example:input":{"x":"0"}}' $RCPROTO://localhost/restconf/operations/clixon-example:example)" 0 'Content-Type: application/yang-data+xml' '042' new "restconf example rpc xml/xml" expectpart "$(curl $CURLOPTS -X POST -H 'Content-Type: application/yang-data+xml' -H 'Accept: application/yang-data+xml' -d '0' $RCPROTO://localhost/restconf/operations/clixon-example:example)" 0 'Content-Type: application/yang-data+xml' '042' new "restconf example rpc xml in w json encoding (expect fail)" expectpart "$(curl $CURLOPTS -X POST -H 'Content-Type: application/yang-data+json' -H 'Accept: application/yang-data+xml' -d '0' $RCPROTO://localhost/restconf/operations/clixon-example:example)" 0 'HTTP/1.1 400 Bad Request' "rpcmalformed-messageerrorjson_parse: line 1: syntax error at or before: '<'" new "restconf example rpc json in xml encoding (expect fail)" expectpart "$(curl $CURLOPTS -X POST -H 'Content-Type: application/yang-data+xml' -H 'Accept: application/yang-data+xml' -d '{"clixon-example:input":{"x":"0"}}' $RCPROTO://localhost/restconf/operations/clixon-example:example)" 0 'HTTP/1.1 400 Bad Reques' 'rpcmalformed-messageerrorxml_parse: line 0: syntax error: at or before: "' new "netconf example rpc" expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO0]]>]]>" "^042]]>]]>$" # 2. Then error cases # new "restconf empty rpc with null input" ret=$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":null}' $RCPROTO://localhost/restconf/operations/clixon-example:empty) expect="204 No Content" match=`echo $ret | grep --null -Eo "$expect"` if [ -z "$match" ]; then err "$expect" "$ret" fi new "restconf empty rpc with input x" expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":0}}' $RCPROTO://localhost/restconf/operations/clixon-example:empty)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"x"},"error-severity":"error","error-message":"Unrecognized parameter: x in rpc: empty"}}}' # cornercase: optional has yang input/output sections but test without body new "restconf optional rpc with null input and output" ret=$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":null}' $RCPROTO://localhost/restconf/operations/clixon-example:optional) expect="204 No Content" match=`echo $ret | grep --null -Eo "$expect"` if [ -z "$match" ]; then err "$expect" "$ret" fi new "restconf omit mandatory" expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":null}' $RCPROTO://localhost/restconf/operations/clixon-example:example)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"x"},"error-severity":"error","error-message":"Mandatory variable of example in module clixon-example"}}} ' new "restconf add extra w/o yang: should fail" if ! $YANG_UNKNOWN_ANYDATA ; then expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":"0","extra":"0"}}' $RCPROTO://localhost/restconf/operations/clixon-example:example)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"unknown-element","error-info":{"bad-element":"extra"},"error-severity":"error","error-message":"Failed to find YANG spec of XML node: extra with parent: example in namespace: urn:example:clixon"}}}' fi new "restconf wrong method" expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":{"x":"0"}}' $RCPROTO://localhost/restconf/operations/clixon-example:wrong)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"wrong"},"error-severity":"error","error-message":"RPC not defined"}}} ' new "restconf example missing input" expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" -d '{"clixon-example:input":null}' $RCPROTO://localhost/restconf/operations/ietf-netconf:edit-config)" 0 'HTTP/1.1 400 Bad Request' '{"ietf-restconf:errors":{"error":{"error-type":"application","error-tag":"missing-element","error-info":{"bad-element":"target"},"error-severity":"error","error-message":"Mandatory variable of edit-config in module ietf-netconf"}}} ' new "netconf kill-session missing session-id mandatory" expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO]]>]]>" "^applicationmissing-elementsession-iderrorMandatory variable of kill-session in module ietf-netconf]]>]]>$" new "netconf edit-config ok" expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO]]>]]>" "^]]>]]>$" if ! $YANG_UNKNOWN_ANYDATA ; then new "netconf edit-config extra arg: should fail" expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO]]>]]>" "^applicationunknown-elementextraerrorFailed to find YANG spec of XML node: extra with parent: edit-config in namespace: urn:ietf:params:xml:ns:netconf:base:1.0]]>]]>$" fi new "netconf edit-config empty target: should fail" expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO]]>]]>" "^applicationdata-missingmissing-choiceconfig-targeterror]]>]]>$" new "netconf edit-config missing target: should fail" expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO]]>]]>" "^applicationmissing-elementtargeterrorMandatory variable of edit-config in module ietf-netconf]]>]]>$" new "netconf edit-config missing config: should fail" expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO]]>]]>" "^applicationdata-missingmissing-choiceedit-contenterror]]>]]>$" # Negative errors (namespace/module missing) new "netconf wrong rpc namespace: should fail" expecteof "$clixon_netconf -qf $cfg" 0 "]]>]]>" "^applicationunknown-elementgeterrorUnrecognized RPC (wrong namespace?)]]>]]>$" new "restconf wrong rpc: should fail" expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" $RCPROTO://localhost/restconf/operations/clixon-foo:get)" 0 'HTTP/1.1 412 Precondition Failed' '{"ietf-restconf:errors":{"error":{"error-type":"protocol","error-tag":"operation-failed","error-severity":"error","error-message":"yang module not found"}}}' # test rpc lists with / without keys LIST='foobarbar' # On docker /fcgi the return is bar,foo,bar new "netconf example rpc input list without key with non-unique entries" ret=$($clixon_netconf -qf $cfg <mandatory$LIST]]>]]> EOF ) r=$? if [ $r -ne 0 ]; then err "0" "$r" fi for expect in "^mandatory42" '' 'foobar' "]]>]]>$"; do new "expect:$expect" match=`echo $ret | grep --null -Eo "$expect"` if [ -z "$match" ]; then err "$expect" "$ret" fi done LIST='bar1foo2' new "netconf example rpc input list with key" expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLOmandatory$LIST]]>]]>" "^mandatory42$LIST]]>]]>$" LIST='bar12' new "netconf example rpc input key list without key (should fail)" expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLOmandatory$LIST]]>]]>" "^applicationmissing-elementukerrorMandatory key]]>]]>$" LIST='bar1bar2' new "netconf example rpc input list with non-unique keys (should fail)" expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLOmandatory$LIST]]>]]>" "^applicationoperation-faileddata-not-uniqueerrorbar]]>]]>$" if [ $RC -ne 0 ]; then new "Kill restconf daemon" stop_restconf 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 # Set by restconf_config unset RESTCONFIG rm -rf $dir new "endtest" endtest