Improving net test tools and scenarios.

Change-Id: I2b53fa7b28e1135d2356ae58d4ee8ac35184d9b8
diff --git a/tools/build/envDefaults b/tools/build/envDefaults
index 6b4cef7..38a1bc1 100644
--- a/tools/build/envDefaults
+++ b/tools/build/envDefaults
@@ -43,3 +43,4 @@
 export ONOS_USER="${ONOS_USER:-sdn}"    # ONOS user on remote system
 export ONOS_GROUP="${ONOS_GROUP:-sdn}"  # ONOS group on remote system
 export ONOS_PWD="rocks"                 # ONOS user password on remote system
+export ONOS_SCENARIOS=$ONOS_ROOT/tools/test/scenarios
diff --git a/tools/dev/bash_profile b/tools/dev/bash_profile
index 8752082..b78f5cd 100644
--- a/tools/dev/bash_profile
+++ b/tools/dev/bash_profile
@@ -30,6 +30,8 @@
 # Setup cell enviroment
 export ONOS_CELL=${ONOS_CELL:-local}
 
+export ONOS_SCENARIOS=$ONOS_ROOT/tools/test/scenarios
+
 # Convenience utility to warp to various ONOS source projects
 # e.g. 'o api', 'o dev', 'o'
 function o {
diff --git a/tools/test/bin/onos-check-summary b/tools/test/bin/onos-check-summary
index daa5253..008506e 100755
--- a/tools/test/bin/onos-check-summary
+++ b/tools/test/bin/onos-check-summary
@@ -10,9 +10,11 @@
 cat $aux
 
 let status=0
-grep -q "nodes=$2" $aux || let status=status+1
-grep -q "devices=$3" $aux || let status=status+1
-grep -q "links=$4" $aux || let status=status+1
-grep -q "hosts=$5" $aux || let status=status+1
+grep -q "nodes=${2:-.*}" $aux || let status=status+1
+grep -q "devices=${3:-.*}" $aux || let status=status+1
+grep -q "links=${4:-.*}" $aux || let status=status+1
+grep -q "hosts=${5:-.*}" $aux || let status=status+1
+grep -q "flows=${6:-.*}" $aux || let status=status+1
+grep -q "intents=${7:-.*}" $aux || let status=status+1
 
 exit $status
\ No newline at end of file
diff --git a/tools/test/bin/onos-mininet b/tools/test/bin/onos-mininet
index 5c03c06..5bcd2f5 100755
--- a/tools/test/bin/onos-mininet
+++ b/tools/test/bin/onos-mininet
@@ -17,8 +17,9 @@
     ;;
 
 sendAndExpect)
-    $mininet -X "stuff \"$1\\n\"" 2>/dev/null
-    shift
+    cmd=""
+    for a in $*; do shift; if [ "$a" = "--expect" ]; then break; fi; cmd="$cmd $a"; done
+    $mininet -X "stuff \"$cmd\\n\"" 2>/dev/null
     onos-mininet expect "$@"
     ;;
 
@@ -33,7 +34,9 @@
 expect)
     aux=/tmp/mininet.$$.log
     ssh $remote "
-        sleep 1 && while ! (tail -n1 $log | egrep -q '^mininet>'); do sleep 1; done
+        sleep 1
+        if [ ! -f $log ]; then exit 1; fi;
+        while ! (tail -n1 $log | egrep -q '^mininet>'); do sleep 1; done
         tac $log | awk '{ print \$0; } /^mininet>/ { if (on) { exit 0; } on=1; }' | tac > $aux
         cat $aux
         set -x
@@ -42,10 +45,12 @@
     ;;
 
 start)
-    ssh $remote rm -f $log
+    ssh $remote "rm -f $log; echo logfile flush 1 > ~/.screenrc"
+    (
     $mininet "$@"
     scp $remote:$log /tmp/mininet.log
     ssh $remote rm -f $log
+    ) &
     ;;
 
 stop)
diff --git a/tools/test/bin/onos-wipe-out b/tools/test/bin/onos-wipe-out
new file mode 100755
index 0000000..4384fc2
--- /dev/null
+++ b/tools/test/bin/onos-wipe-out
@@ -0,0 +1,11 @@
+#!/bin/bash
+# -----------------------------------------------------------------------------
+# Wipes out all data from the ONOS cluster. Temporary until wipe-out is fixed.
+# -----------------------------------------------------------------------------
+
+[ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1
+. $ONOS_ROOT/tools/build/envDefaults
+
+while ! onos-check-summary $OCI '.*' 0 0 0 0 0; do
+    onos $OCI wipe-out please
+done
diff --git a/tools/test/scenarios/basic-net.xml b/tools/test/scenarios/basic-net.xml
deleted file mode 100644
index a574cba..0000000
--- a/tools/test/scenarios/basic-net.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<!--
-  ~ Copyright 2015 Open Networking Laboratory
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~     http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<scenario name="basic-net" description="Basic network functionality test">
-    <group name="Basic-Net">
-        <step name="Push-Topos" exec="onos-push-topos ${OCN}"/>
-
-        <step name="Install-Apps"
-              exec="onos ${OC1} app activate org.onosproject.openflow org.onosproject.proxyarp org.onosproject.fwd"/>
-        <step name="Check-Apps" requires="Install-Apps"
-              exec="onos-check-apps ${OC1} drivers,openflow,proxyarp,fwd"/>
-
-        <step name="Wipe-Out-Data" requires="~Check-Apps"
-              exec="onos ${OC1} wipe-out please"/>
-
-        <step name="Check-Summary" requires="~Wipe-Out-Data"
-              exec="onos-check-summary ${OC1} [0-9]* 0 0 0"/>
-
-        <step name="Start-Mininet" requires="Install-Apps,Check-Summary,Push-Topos"
-              exec="onos-mininet start topos/att-onos ${ONOS_INSTANCES}"/>
-
-        <step name="Wait-For-Mininet" requires="Install-Apps,Check-Summary"
-              exec="onos-mininet wait 15"/>
-
-        <step name="Check-Summary-Again" requires="Wait-For-Mininet"
-              exec="onos-check-summary ${OC1} [0-9]* 25 112 0"/>
-
-        <step name="Config-Topo" requires="Check-Summary-Again"
-              exec="onos-topo-cfg ${OC1} ${ONOS_ROOT}/tools/test/topos/attmpls.json"/>
-
-        <step name="Check-Summary-Yet-Again" requires="~Config-Topo"
-              exec="onos-check-summary ${OC1} [0-9]* 25 112 25"/>
-
-        <step name="Ping-All" requires="Wait-For-Mininet,~Check-Summary-Again"
-              exec="onos-mininet send py net.pingAll(1)"/>
-
-        <step name="Verify-Ping-All" requires="~Ping-All"
-              exec="onos-mininet expect Results: .* dropped"/>
-
-        <step name="Stop-Mininet" requires="~Verify-Ping-All"
-              exec="onos-mininet stop"/>
-    </group>
-</scenario>
\ No newline at end of file
diff --git a/tools/test/scenarios/net-link-up-down.xml b/tools/test/scenarios/net-link-up-down.xml
new file mode 100644
index 0000000..f421227
--- /dev/null
+++ b/tools/test/scenarios/net-link-up-down.xml
@@ -0,0 +1,38 @@
+<!--
+  ~ Copyright 2015 Open Networking Laboratory
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<scenario name="net-link-up-down" description="Network link up-down test">
+    <!-- TODO: parametrize this via recipes -->
+    <group name="Net-Link-Up-Down">
+        <step name="Ping-1"
+              exec="onos-mininet sendAndExpect h1 ping -c1 h4 --expect \ 0% packet loss"/>
+        <step name="Link-1-Down" requires="Ping-1"
+              exec="onos-mininet sendAndExpect link s4 s5 down --expect ."/>
+        <step name="Ping-2" requires="Link-1-Down"
+              exec="onos-mininet sendAndExpect h1 ping -c1 h4 --expect \ 0% packet loss"/>
+        <step name="Link-2-Down" requires="Ping-2"
+              exec="onos-mininet sendAndExpect link s4 s7 down --expect ."/>
+        <step name="Ping-3" requires="Link-2-Down"
+              exec="onos-mininet sendAndExpect h1 ping -c1 h4 --expect 100% packet loss"/>
+        <step name="Link-1-Up" requires="Ping-3"
+              exec="onos-mininet sendAndExpect link s4 s7 up --expect ."/>
+        <step name="Ping-4" requires="Link-1-Up"
+              exec="onos-mininet sendAndExpect h1 ping -c1 h4 --expect \ 0% packet loss"/>
+        <step name="Link-2-Up" requires="Ping-4"
+              exec="onos-mininet sendAndExpect link s4 s5 up --expect ."/>
+        <step name="Ping-5" requires="Link-2-Up"
+              exec="onos-mininet sendAndExpect h1 ping -c1 h4 --expect \ 0% packet loss"/>
+    </group>
+</scenario>
\ No newline at end of file
diff --git a/tools/test/scenarios/net-pingall.xml b/tools/test/scenarios/net-pingall.xml
new file mode 100644
index 0000000..70ce510
--- /dev/null
+++ b/tools/test/scenarios/net-pingall.xml
@@ -0,0 +1,28 @@
+<!--
+  ~ Copyright 2015 Open Networking Laboratory
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<scenario name="net-pingall" description="Network pingall test">
+    <!-- TODO: parametrize this via recipes -->
+    <group name="Net-Pingall">
+        <step name="Ping-All-And-Verify"
+              exec="onos-mininet sendAndExpect py net.pingAll(1) --expect Results: .* dropped"/>
+
+        <step name="Check-Summary-For-Hosts" requires="~Ping-All-And-Verify"
+              exec="onos-check-summary ${OC1} [0-9]* 25 112 25"/>
+
+        <step name="Config-Topo" requires="Check-Summary-For-Hosts"
+              exec="onos-topo-cfg ${OC1} ${ONOS_ROOT}/tools/test/topos/attmpls.json"/>
+    </group>
+</scenario>
\ No newline at end of file
diff --git a/tools/test/scenarios/net-setup.xml b/tools/test/scenarios/net-setup.xml
new file mode 100644
index 0000000..95347f0
--- /dev/null
+++ b/tools/test/scenarios/net-setup.xml
@@ -0,0 +1,45 @@
+<!--
+  ~ Copyright 2015 Open Networking Laboratory
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<scenario name="net-setup" description="Network setup steps">
+    <!-- TODO: parametrize this via recipes -->
+    <group name="Net-Setup">
+        <step name="Push-Topos" exec="onos-push-topos ${OCN}"/>
+
+        <step name="Install-Apps"
+              exec="onos ${OC1} app activate org.onosproject.openflow org.onosproject.proxyarp org.onosproject.fwd"/>
+
+        <step name="Check-Apps" requires="Install-Apps"
+              exec="onos-check-apps ${OC1} drivers,openflow,proxyarp,fwd"/>
+
+        <step name="Wipe-Out-Data-Before" requires="~Check-Apps" exec="onos-wipe-out"/>
+
+        <step name="Initial-Summary-Check" requires="~Wipe-Out-Data-Before"
+              exec="onos-check-summary ${OC1} [0-9]* 0 0 0"/>
+
+        <step name="Start-Mininet"
+              requires="Install-Apps,Initial-Summary-Check,Push-Topos"
+              exec="onos-mininet start topos/topo att-onos.py ${ONOS_INSTANCES}"/>
+
+        <step name="Wait-For-Mininet" requires="Start-Mininet"
+              exec="onos-mininet wait 15"/>
+
+        <step name="Check-Summary" requires="Wait-For-Mininet"
+              exec="onos-check-summary ${OC1} [0-9]* 25 112 0"/>
+
+        <step name="Balance-Masters" requires="Check-Summary"
+              exec="onos ${OC1} balance-masters"/>
+    </group>
+</scenario>
\ No newline at end of file
diff --git a/tools/test/scenarios/net-smoke.xml b/tools/test/scenarios/net-smoke.xml
new file mode 100644
index 0000000..fec1652
--- /dev/null
+++ b/tools/test/scenarios/net-smoke.xml
@@ -0,0 +1,29 @@
+<!--
+  ~ Copyright 2015 Open Networking Laboratory
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<scenario name="net-smoke" description="Basic network functionality smoke test">
+    <group name="Net-Smoke">
+        <import file="${ONOS_SCENARIOS}/net-setup.xml"/>
+
+        <import file="${ONOS_SCENARIOS}/net-pingall.xml"/>
+        <dependency name="Net-Pingall" requires="Net-Setup"/>
+
+        <import file="${ONOS_SCENARIOS}/net-link-up-down.xml"/>
+        <dependency name="Net-Link-Up-Down" requires="~Net-Pingall"/>
+
+        <import file="${ONOS_SCENARIOS}/net-teardown.xml"/>
+        <dependency name="Net-Teardown" requires="~Net-Link-Up-Down"/>
+    </group>
+</scenario>
\ No newline at end of file
diff --git a/tools/test/scenarios/net-teardown.xml b/tools/test/scenarios/net-teardown.xml
new file mode 100644
index 0000000..fa52ce3
--- /dev/null
+++ b/tools/test/scenarios/net-teardown.xml
@@ -0,0 +1,21 @@
+<!--
+  ~ Copyright 2015 Open Networking Laboratory
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<scenario name="net-setup" description="Network teardown steps">
+    <group name="Net-Teardown">
+        <step name="Stop-Mininet" exec="onos-mininet stop"/>
+        <step name="Wipe-Out-Data-After" requires="~Stop-Mininet" exec="onos-wipe-out"/>
+    </group>
+</scenario>
\ No newline at end of file
diff --git a/tools/test/scenarios/smoke.xml b/tools/test/scenarios/smoke.xml
index 27818ee..1614f78 100644
--- a/tools/test/scenarios/smoke.xml
+++ b/tools/test/scenarios/smoke.xml
@@ -14,17 +14,17 @@
   ~ limitations under the License.
   -->
 <scenario name="smoke-test" description="ONOS smoke test">
-    <import file="${ONOS_ROOT}/tools/test/scenarios/prerequisites.xml"/>
+    <import file="${ONOS_SCENARIOS}/prerequisites.xml"/>
 
-    <import file="${ONOS_ROOT}/tools/test/scenarios/setup.xml"/>
+    <import file="${ONOS_SCENARIOS}/setup.xml"/>
     <dependency name="Setup" requires="Prerequisites"/>
 
-    <import file="${ONOS_ROOT}/tools/test/scenarios/basic-net.xml"/>
-    <dependency name="Basic-Net" requires="Setup"/>
+    <import file="${ONOS_SCENARIOS}/net-smoke.xml"/>
+    <dependency name="Net-Smoke" requires="Setup"/>
 
-    <import file="${ONOS_ROOT}/tools/test/scenarios/archetypes.xml"/>
-    <dependency name="Archetypes" requires="~Basic-Net,Setup"/>
+    <import file="${ONOS_SCENARIOS}/archetypes.xml"/>
+    <dependency name="Archetypes" requires="~Net-Smoke,Setup"/>
 
-    <import file="${ONOS_ROOT}/tools/test/scenarios/wrapup.xml"/>
-    <dependency name="Wrapup" requires="~Archetypes,~Setup,~Basic-Net"/>
+    <import file="${ONOS_SCENARIOS}/wrapup.xml"/>
+    <dependency name="Wrapup" requires="~Archetypes,~Setup,~Net-Smoke"/>
 </scenario>
diff --git a/tools/test/topos/att-onos b/tools/test/topos/att-onos
index e473359..9ad918a 100755
--- a/tools/test/topos/att-onos
+++ b/tools/test/topos/att-onos
@@ -1,3 +1,7 @@
+#!/bin/bash
+# -----------------------------------------------------------------------------
+# Starts ATT ONOS topology in mininet.
+# -----------------------------------------------------------------------------
 cd $(dirname $0)
 if [ -n "$1" ]; then
     sudo python att-onos.py "$@"
diff --git a/tools/test/topos/rftest.py b/tools/test/topos/rftest.py
new file mode 100644
index 0000000..7aba54f
--- /dev/null
+++ b/tools/test/topos/rftest.py
@@ -0,0 +1,40 @@
+#!/usr/bin/python
+
+import sys
+
+from mininet.net import Mininet
+from mininet.cli import CLI
+from mininet.log import setLogLevel
+from mininet.node import RemoteController
+
+from rftesttopo import ReactiveForwardingTestTopo
+
+setLogLevel( 'info' )
+
+def pingloop( net ):
+    setLogLevel( 'error' )
+    try:
+        while True:
+            net.ping()
+    finally:
+        setLogLevel( 'info' )
+
+def run(controllers=[ '127.0.0.1' ]):
+    Mininet.pingloop = pingloop
+    net = Mininet( topo=ReactiveForwardingTestTopo(), build=False, autoSetMacs=True )
+    ctrl_count = 0
+    for controllerIP in controllers:
+        net.addController( 'c%d' % ctrl_count, RemoteController, ip=controllerIP )
+	ctrl_count = ctrl_count + 1
+    net.build()
+    net.start()
+    CLI( net )
+    net.stop()
+
+if __name__ == '__main__':
+    if len( sys.argv ) > 1:
+        controllers = sys.argv[ 1: ]
+    else:
+        print 'Usage: rf-test.py <c0 IP> <c1 IP> ...'
+        exit( 1 )
+    run( controllers )
diff --git a/tools/test/topos/rftesttopo.py b/tools/test/topos/rftesttopo.py
new file mode 100644
index 0000000..9b97578
--- /dev/null
+++ b/tools/test/topos/rftesttopo.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+
+"""
+"""
+from mininet.topo import Topo
+from mininet.net import Mininet
+from mininet.node import RemoteController
+from mininet.node import Node
+from mininet.node import CPULimitedHost
+from mininet.link import TCLink
+from mininet.cli import CLI
+from mininet.log import setLogLevel
+from mininet.util import dumpNodeConnections
+
+class ReactiveForwardingTestTopo( Topo ):
+    "Internet Topology Zoo Specimen."
+
+    def __init__( self ):
+        "Create a topology."
+
+        # Initialize Topology
+        Topo.__init__( self )
+
+        # add nodes, switches first...
+        s1 = self.addSwitch( 's1' )
+        s2 = self.addSwitch( 's2' )
+        s3 = self.addSwitch( 's3' )
+        s4 = self.addSwitch( 's4' )
+        s5 = self.addSwitch( 's5' )
+        s6 = self.addSwitch( 's6' )
+        s7 = self.addSwitch( 's7' )
+        s8 = self.addSwitch( 's8' )
+        s9 = self.addSwitch( 's9' )
+
+        # ... and now hosts
+        h1 = self.addHost( 'h1' )
+        h2 = self.addHost( 'h2' )
+        h3 = self.addHost( 'h3' )
+        h4 = self.addHost( 'h4' )
+
+        # add edges between switch and corresponding host
+        self.addLink( s1 , h1 )
+        self.addLink( s2 , h2 )
+        self.addLink( s3 , h3 )
+        self.addLink( s4 , h4 )
+
+        # add edges between switches
+        self.addLink( s1 , s5 )
+        self.addLink( s2 , s5 )
+        self.addLink( s2 , s8 )
+        self.addLink( s3 , s4 )
+        self.addLink( s3 , s7 )
+        self.addLink( s4 , s5 )
+        self.addLink( s6 , s8 )
+        self.addLink( s6 , s7 )
+        self.addLink( s5 , s9 )
+        self.addLink( s6 , s9 )
+
+topos = { 'att': ( lambda: ReactiveForwardingTestTopo() ) }
diff --git a/tools/test/topos/topo b/tools/test/topos/topo
new file mode 100755
index 0000000..854de50
--- /dev/null
+++ b/tools/test/topos/topo
@@ -0,0 +1,10 @@
+#!/bin/bash
+# -----------------------------------------------------------------------------
+# Starts the specified mininet topology.
+# -----------------------------------------------------------------------------
+cd $(dirname $0)
+
+topo=${1:-att-onos.py}
+
+[ -n "$1" ] && shift
+sudo python $topo "$@"