1#!/usr/bin/env bash 2# Transaction functionality 3# The test uses two backend plugins (main and nacm) that logs to a file and a 4# netconf client to push operation. The tests then look at the log. 5# The test assumes the two plugins recognize the -- -t argument which includes 6# that one of them fails at validation at one point 7# The tests are as follows (first five only callbacks per se; then data vector tests) 8# 1. Validate-only transaction 9# 2. Commit transaction 10# 3. Validate system-error (invalid type detected by system) 11# 4. Validate user-error (invalidation by user callback) 12# 5. Commit user-error (invalidation by user callback) 13# -- to here only basic callback tests (that they occur). Below transaction data 14# 6. Detailed transaction vector add/del/change tests 15# For the last test, the yang is a list with three members, so that you can do 16# add/delete/change in a single go. 17# The user-error uses a trick feature in the example nacm plugin which is started 18# with an "error-trigger" xpath which triggers an error. This also toggles between 19# validation and commit errors 20 21# Magic line must be first in script (see README.md) 22s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi 23 24APPNAME=example 25 26cfg=$dir/conf_yang.xml 27fyang=$dir/trans.yang 28flog=$dir/backend.log 29touch $flog 30 31# Used as a trigger for user-validittion errors, eg <a>$errnr</a> = <a>42</a> is invalid 32errnr=42 33 34cat <<EOF > $fyang 35module trans{ 36 yang-version 1.1; 37 namespace "urn:example:clixon"; 38 prefix ex; 39 container x { 40 list y { 41 key "a"; 42 leaf a { 43 type int32; 44 } 45 leaf b { 46 description "change this (also use to check invalid)"; 47 type int32{ 48 range "0..100"; 49 } 50 } 51 leaf c { 52 description "del this"; 53 type int32; 54 } 55 leaf d { 56 description "add this"; 57 type int32; 58 } 59 } 60 } 61} 62EOF 63 64cat <<EOF > $cfg 65<clixon-config xmlns="http://clicon.org/config"> 66 <CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE> 67 <CLICON_YANG_DIR>/usr/local/share/clixon</CLICON_YANG_DIR> 68 <CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE> 69 <CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR> 70 <CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR> 71 <CLICON_NETCONF_DIR>/usr/local/lib/$APPNAME/netconf</CLICON_NETCONF_DIR> 72 <CLICON_RESTCONF_DIR>/usr/local/lib/$APPNAME/restconf</CLICON_RESTCONF_DIR> 73 <CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR> 74 <CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE> 75 <CLICON_SOCK>$dir/$APPNAME.sock</CLICON_SOCK> 76 <CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE> 77 <CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR> 78</clixon-config> 79EOF 80 81# Check statements in log 82# arg1: a statement to look for 83# arg2: expected line number 84checklog(){ 85 s=$1 # statement 86 l0=$2 # linenr 87 new "Check $s in log" 88# echo "grep \"transaction_log $s line:$l0\" $flog" 89 t=$(grep -n "transaction_log $s" $flog) 90 if [ -z "$t" ]; then 91 echo -e "\e[31m\nError in Test$testnr [$testname]:" 92 if [ $# -gt 0 ]; then 93 echo "Not found in log" 94 echo 95 fi 96 echo -e "\e[0m" 97 exit -1 98 fi 99 l1=$(echo "$t" | awk -F ":" '{print $1}') 100 if [ $l1 -ne $l0 ]; then 101 echo -e "\e[31m\nError in Test$testnr [$testname]:" 102 if [ $# -gt 0 ]; then 103 echo "Expected match on line $l0, found on $l1" 104 echo 105 fi 106 echo -e "\e[0m" 107 exit -1 108 fi 109} 110 111new "test params: -f $cfg -l f$flog -- -t -v /x/y[a=$errnr]" # Fail on this 112# Bring your own backend 113if [ $BE -ne 0 ]; then 114 # kill old backend (if any) 115 new "kill old backend" 116 sudo clixon_backend -zf $cfg 117 if [ $? -ne 0 ]; then 118 err 119 fi 120 new "start backend -s init -f $cfg -l f$flog -- -t -v /x/y[a=$errnr]" 121 start_backend -s init -f $cfg -l f$flog -- -t -v /x/y[a=$errnr] # -t means transaction logging 122 123 new "waiting" 124 wait_backend 125fi 126 127let nr=0 128 129new "Basic transaction to add top-level x" 130expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><x xmlns='urn:example:clixon'><y><a>$nr</a></y></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$" 131 132new "Commit base" 133expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><commit/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$" 134 135let line=14 # Skipping basic transaction 136 137# 1. validate(-only) transaction 138let nr++ 139let line 140new "1. Validate-only transaction" 141expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><x xmlns='urn:example:clixon'><y><a>$nr</a></y></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$" 142 143new "Validate-only validate" 144expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$" 145 146xml="<y><a>$nr</a></y>" 147for op in begin validate complete end; do 148 checklog "$nr main_$op add: $xml" $line 149 let line++ 150 checklog "$nr nacm_$op add: $xml" $line 151 let line++ 152done 153 154new "Validate-only discard-changes" 155expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><discard-changes/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$" 156 157# 2. Commit transaction 158let nr++ 159new "2. Commit transaction config" 160expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><x xmlns='urn:example:clixon'><y><a>$nr</a></y></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$" 161 162new "Commit transaction: commit" 163expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><commit/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$" 164 165xml="<y><a>$nr</a></y>" 166for op in begin validate complete commit commit_done end; do 167 checklog "$nr main_$op add: $xml" $line 168 let line++ 169 checklog "$nr nacm_$op add: $xml" $line 170 let line++ 171done 172 173# 3. Validate only system-error (invalid type detected by system) 174let nr++ 175new "3. Validate system-error config (9999 not in range)" 176expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><x xmlns='urn:example:clixon'><y><a>$nr</a><b>9999</b></y></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$" 177 178new "Validate system-error validate (should fail)" 179expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>b</bad-element></error-info><error-severity>error</error-severity><error-message>Number 9999 out of range: 0 - 100</error-message></rpc-error></rpc-reply>]]>]]>$" 180 181new "Validate system-error discard-changes" 182expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><discard-changes/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$" 183 184for op in begin abort; do 185 checklog "$nr main_$op add: <y><a>$nr</a><b>9999</b></y>" $line 186 let line++ 187 checklog "$nr nacm_$op add: <y><a>$nr</a><b>9999</b></y>" $line 188 let line++ 189done 190 191# 4. Validate only user-error (invalidation by user callback) 192let nr++ 193new "4. Validate user-error config ($errnr is invalid)" 194expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><x xmlns='urn:example:clixon'><y><a>$errnr</a></y></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$" 195 196new "Validate user-error validate (should fail)" 197expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><validate><source><candidate/></source></validate></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>User error</error-message></rpc-error></rpc-reply>]]>]]>$" 198 199new "Validate user-error discard-changes" 200expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><discard-changes/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$" 201 202for op in begin validate; do 203 checklog "$nr main_$op add: <y><a>$errnr</a></y>" $line 204 let line++ 205 checklog "$nr nacm_$op add: <y><a>$errnr</a></y>" $line 206 let line++ 207done 208let line++ # error message 209for op in abort; do 210 checklog "$nr main_$op add: <y><a>$errnr</a></y>" $line 211 let line++ 212 checklog "$nr nacm_$op add: <y><a>$errnr</a></y>" $line 213 let line++ 214done 215 216# 5. Commit user-error (invalidation by user callback) 217# XXX Note Validate-only user-error must immediately preceede this due to toggling 218# in nacm/transaction example test module 219let nr++ 220new "5. Commit user-error ($errnr is invalid)" 221expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><x xmlns='urn:example:clixon'><y><a>$errnr</a></y></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$" 222 223new "Commit user-error commit" 224expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><commit/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><rpc-error><error-type>application</error-type><error-tag>operation-failed</error-tag><error-severity>error</error-severity><error-message>User error</error-message></rpc-error></rpc-reply>]]>]]>$" 225 226new "Commit user-error discard-changes" 227expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><discard-changes/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$" 228 229for op in begin validate complete commit ; do 230 checklog "$nr main_$op add: <y><a>$errnr</a></y>" $line 231 let line++ 232 checklog "$nr nacm_$op add: <y><a>$errnr</a></y>" $line 233 let line++ 234done 235 236let line++ # error message 237checklog "$nr main_revert add: <y><a>$errnr</a></y>" $line 238let line++ 239for op in abort; do 240 checklog "$nr main_$op add: <y><a>$errnr</a></y>" $line 241 let line++ 242 checklog "$nr nacm_$op add: <y><a>$errnr</a></y>" $line 243 let line++ 244done 245 246# 6. Detailed transaction vector add/del/change tests 247let nr++ 248let base=nr 249new "Add base <a>$base entry" 250expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><x xmlns='urn:example:clixon'><y><a>$base</a><b>0</b><c>0</c></y></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$" 251 252new "netconf commit base" 253expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><commit/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$" 254#Ignore 255let line+=12 256 257let nr++ 258new "6. netconf mixed change: change b, del c, add d" 259expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><x xmlns='urn:example:clixon'><y><a>$base</a><b>42</b><d>0</d></y></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$" 260 261new "netconf commit change" 262expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><commit/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$" 263 264# Check complete transaction $nr: 265for op in begin validate complete commit commit_done; do 266 checklog "$nr main_$op add: <d>0</d>" $line 267 let line++ 268 checklog "$nr main_$op change: <b>0</b><b>42</b>" $line 269 let line++ 270 checklog "$nr nacm_$op add: <d>0</d>" $line 271 let line++ 272 checklog "$nr nacm_$op change: <b>0</b><b>42</b>" $line 273 let line++ 274done 275 276# End is special because change does not have old element 277checklog "$nr main_end add: <d>0</d>" $line 278let line++ 279# This check does not work if MOVE_TRANS_END is set 280checklog "$nr main_end change: <b>42</b>" $line 281let line+=3 # skip nacm 282 283let nr++ 284let base=nr 285new "Add base <a>$base entry" 286expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><x xmlns='urn:example:clixon'><y><a>$base</a><d>1</d></y></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$" 287 288new "netconf commit base" 289expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><commit/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$" 290let line+=12 291 292# Variant check that only b,c 293let nr++ 294new "7. netconf insert b,c between end-points" 295expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><x xmlns='urn:example:clixon'><y><a>$base</a><b>1</b><c>1</c></y></x></config></edit-config></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$" 296 297new "netconf commit base" 298expecteof "$clixon_netconf -qf $cfg" 0 "<rpc $DEFAULTNS><commit/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$" 299 300# check complete 301for op in begin validate complete commit commit_done end; do 302 checklog "$nr main_$op add: <b>1</b><c>1</c>" $line 303 let line++ 304 checklog "$nr nacm_$op add: <b>1</b><c>1</c>" $line 305 let line++ 306done 307 308if [ $BE -eq 0 ]; then 309 exit # BE 310fi 311 312new "Kill backend" 313# Check if premature kill 314pid=$(pgrep -u root -f clixon_backend) 315if [ -z "$pid" ]; then 316 err "backend already dead" 317fi 318# kill backend 319stop_backend -f $cfg 320 321rm -rf $dir 322 323unset nr 324