#!/usr/bin/env bash # Transaction functionality # The test uses two backend plugins (main and nacm) that logs to a file and a # netconf client to push operation. The tests then look at the log. # The test assumes the two plugins recognize the -- -t argument which includes # that one of them fails at validation at one point # The tests are as follows (first five only callbacks per se; then data vector tests) # 1. Validate-only transaction # 2. Commit transaction # 3. Validate system-error (invalid type detected by system) # 4. Validate user-error (invalidation by user callback) # 5. Commit user-error (invalidation by user callback) # -- to here only basic callback tests (that they occur). Below transaction data # 6. Validate user-error with plugin_rpc_err (invalidation by user callback) # 7. Detailed transaction vector add/del/change tests # For the last test, the yang is a list with three members, so that you can do # add/delete/change in a single go. # The user-error uses a trick feature in the example nacm plugin which is started # with an "error-trigger" xpath which triggers an error. This also toggles between # validation and commit errors # 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/trans.yang flog=$dir/backend.log touch $flog # Used as a trigger for user-validation errors, eg $errnr = 42 is invalid errnr=42 cat < $fyang module trans{ yang-version 1.1; namespace "urn:example:clixon"; prefix ex; container x { list y { key "a"; leaf a { type int32; } leaf b { description "change this (also use to check invalid)"; type int32{ range "0..100"; } } leaf c { description "del this"; type int32; } leaf d { description "add this"; type int32; } } choice csame { leaf first { type boolean; } leaf second { type boolean; } } choice cempty { case a{ leaf aaa { type empty; } } case b{ leaf bbb { type boolean; } leaf ccc { type empty; } } } choice canydata { case a{ anydata ddd; } case b{ leaf eee { type boolean; } anydata fff; } } } } EOF cat < $cfg $cfg ${YANG_INSTALLDIR} $fyang /usr/local/lib/$APPNAME/clispec /usr/local/lib/$APPNAME/backend /usr/local/lib/$APPNAME/netconf /usr/local/lib/$APPNAME/restconf /usr/local/lib/$APPNAME/cli $APPNAME $dir/$APPNAME.sock /usr/local/var/run/$APPNAME.pidfile $dir EOF # Check statements in log # arg1: a statement to look for # arg2: expected line number function checklog(){ s=$1 # statement l0=$2 # linenr new "Check $s in log" echo "grep \"transaction_log $s line:$l0\" $flog" t=$(grep -n "transaction_log $s" $flog) if [ -z "$t" ]; then echo -e "\e[31m\nError in Test$testnr [$testname]:" if [ $# -gt 0 ]; then echo "Not found \"$s\" on line $l0" echo fi echo -e "\e[0m" exit -1 fi l1=$(echo "$t" | awk -F ":" '{print $1}') if [ $l1 -ne $l0 ]; then echo -e "\e[31m\nError in Test$testnr [$testname]:" if [ $# -gt 0 ]; then echo "Expected match on line $l0, found on $l1" echo fi echo -e "\e[0m" exit -1 fi } new "test params: -f $cfg -l f$flog -- -t -v /x/y[a=$errnr]" # Fail on this # Bring your own backend if [ $BE -ne 0 ]; then # kill old backend (if any) new "kill old backend" sudo clixon_backend -zf $cfg if [ $? -ne 0 ]; then err fi new "start backend -s init -f $cfg -l f$flog -- -t -v \"/x/y[a='$errnr']\"" start_backend -s init -f $cfg -l f$flog -- -t -v "/x/y[a='$errnr']" # -t means transaction logging fi new "wait backend" wait_backend let nr=0 new "Basic transaction to add top-level x" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "$nr" "" "" new "Commit base" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" let line=14 # Skipping basic transaction # 1. validate(-only) transaction let nr++ let line new "1. Validate-only transaction" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "$nr" "" "" new "Validate-only validate" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" xml="$nr" for op in begin validate complete end; do checklog "$nr main_$op add: $xml" $line let line++ checklog "$nr nacm_$op add: $xml" $line let line++ done new "Validate-only discard-changes" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" # 2. Commit transaction let nr++ new "2. Commit transaction config" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "$nr" "" "" new "Commit transaction: commit" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" xml="$nr" for op in begin validate complete commit commit_done end; do checklog "$nr main_$op add: $xml" $line let line++ checklog "$nr nacm_$op add: $xml" $line let line++ done # 3. Validate only system-error (invalid type detected by system) let nr++ new "3. Validate system-error config (9999 not in range)" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "$nr9999" "" "" new "Validate system-error validate (should fail)" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "applicationbad-elementberrorNumber 9999 out of range: 0 - 100" new "Validate system-error discard-changes" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" for op in begin abort; do checklog "$nr main_$op add: $nr9999" $line let line++ checklog "$nr nacm_$op add: $nr9999" $line let line++ done # 4. Validate only user-error (invalidation by user callback) let nr++ new "4. Validate user-error config ($errnr is invalid)" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "$errnr" "" "" new "Validate user-error validate (should fail)" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "applicationoperation-failederrorUser error" new "Validate user-error discard-changes" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" for op in begin validate; do checklog "$nr main_$op add: $errnr" $line let line++ checklog "$nr nacm_$op add: $errnr" $line let line++ done let line++ # error message for op in abort; do checklog "$nr main_$op add: $errnr" $line let line++ checklog "$nr nacm_$op add: $errnr" $line let line++ done # 5. Commit user-error (invalidation by user callback) # XXX Note Validate-only user-error must immediately preceede this due to toggling # in nacm/transaction example test module let nr++ new "5. Commit user-error ($errnr is invalid)" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "$errnr" "" "" new "Commit user-error commit" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "applicationoperation-failederrorUser error" new "Commit user-error discard-changes" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" for op in begin validate complete commit ; do checklog "$nr main_$op add: $errnr" $line let line++ checklog "$nr nacm_$op add: $errnr" $line let line++ done let line++ # error message checklog "$nr main_revert add: $errnr" $line let line++ for op in abort; do checklog "$nr main_$op add: $errnr" $line let line++ checklog "$nr nacm_$op add: $errnr" $line let line++ done # 6. Validate only user-error with plugin_rpc_err (invalidation by user callback) # XXX Note Commit user-error must immediately preceede this due to toggling # in nacm/transaction example test module let nr++ new "6. Validate user-error with plugin_rpc_err ($errnr is invalid)" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "$errnr99" "" "" new "Validate user-error validate (should fail)" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "applicationtest_error_tagerrortest_error_infotest_error_data 1234" new "Validate user-error discard-changes" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" for op in begin validate; do checklog "$nr main_$op add: $errnr99" $line let line++ checklog "$nr nacm_$op add: $errnr99" $line let line++ done # No error message here, don't increment line. for op in abort; do checklog "$nr main_$op add: $errnr99" $line let line++ checklog "$nr nacm_$op add: $errnr99" $line let line++ done # 7. Detailed transaction vector add/del/change tests let nr++ let base=nr new "Add base $base entry" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "$base00" "" "" new "netconf commit base" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" #Ignore let line+=12 let nr++ new "7. netconf mixed change: change b, del c, add d" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "$base420" "" "" new "netconf commit change" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" # Check complete transaction $nr: for op in begin validate complete commit commit_done; do checklog "$nr main_$op add: 0" $line let line++ checklog "$nr main_$op change: 042" $line let line++ checklog "$nr nacm_$op add: 0" $line let line++ checklog "$nr nacm_$op change: 042" $line let line++ done # End is special because change does not have old element checklog "$nr main_end add: 0" $line let line++ # This check does not work if MOVE_TRANS_END is set checklog "$nr main_end change: 42" $line let line+=3 # skip nacm let nr++ let base=nr new "Add base $base entry" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "$base1" "" "" new "netconf commit base" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" let line+=12 # Variant check that only b,c let nr++ new "8. netconf insert b,c between end-points" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "$base11" "" "" new "netconf commit base" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" # check complete for op in begin validate complete commit commit_done end; do checklog "$nr main_$op add: 11" $line let line++ checklog "$nr nacm_$op add: 11" $line let line++ done new "9. Choice" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "true" "" "" new "netconf commit same" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "Set second choice" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "true" "" "" new "netconf commit second" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" let nr++ let nr++ let line+=12 for op in begin validate complete commit commit_done; do checklog "$nr main_$op del: true" $line let line++ checklog "$nr main_$op add: true" $line let line++ checklog "$nr nacm_$op del: true" $line let line++ checklog "$nr nacm_$op add: true" $line let line++ done # End is special because change does not have old element checklog "$nr main_end add: true" $line let line++ # This check does not work if MOVE_TRANS_END is set checklog "$nr nacm_end add: true" $line let line++ new "10. Choice/case with empty type" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "netconf commit first" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "Set second choice" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "netconf commit second" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" let nr++ let nr++ let line+=12 for op in begin validate complete commit commit_done; do checklog "$nr main_$op del: " $line let line++ checklog "$nr main_$op add: " $line let line++ checklog "$nr nacm_$op del: " $line let line++ checklog "$nr nacm_$op add: " $line let line++ done # End is special because change does not have old element checklog "$nr main_end add: " $line let line++ checklog "$nr nacm_end add: " $line let line++ #--------------------------------------------- new "11. Choice/case with anydata" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "a" "" "" new "netconf commit first" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "Set second choice" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" new "netconf commit second" expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" let nr++ let nr++ let line+=12 for op in begin validate complete commit commit_done; do checklog "$nr main_$op del: a" $line let line++ checklog "$nr main_$op add: " $line let line++ checklog "$nr nacm_$op del: a" $line let line++ checklog "$nr nacm_$op add: " $line let line++ done # End is special because change does not have old element checklog "$nr main_end add: " $line let line++ checklog "$nr nacm_end add: " $line let line++ 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 rm -rf $dir new "endtest" endtest