Changes to docker file and cluster creation, complete stc test on single instance, but not yet on multi-instances Alao, we add detailed checking for every step in ODTN testing.

Change-Id: Id074e2db89a8892ed263880cfa670c4861e011b9
diff --git a/tools/build/envDefaults b/tools/build/envDefaults
index 3f23719..811921b 100644
--- a/tools/build/envDefaults
+++ b/tools/build/envDefaults
@@ -46,12 +46,12 @@
 export ONOS_ADMIN_BITS=onos-admin-${ONOS_VERSION%~*}
 export ONOS_ADMIN_TAR=$ONOS_STAGE_ROOT/$ONOS_ADMIN_BITS.tar.gz
 
-export ONOS_INSTALL_DIR="/opt/onos"     # Installation directory on remote
-export ATOMIX_INSTALL_DIR="/opt/atomix" # Installation directory for Atomix
+export ONOS_INSTALL_DIR="${ONOS_INSTALL_DIR:-/opt/onos}"     # Installation directory on remote
+export ATOMIX_INSTALL_DIR="${ATOMIX_INSTALL_DIR:-/opt/atomix}" # Installation directory for Atomix
 export OCI="${OCI:-localhost}"          # ONOS Controller Instance
 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_PWD="${ONOS_PWD:-rocks}"                 # ONOS user password on remote system
 export ONOS_SCENARIOS=$ONOS_ROOT/tools/test/scenarios
 
 export ONOS_CLUSTER_KEY_FILE="/tmp/onos.jks"
diff --git a/tools/dev/Dockerfile-dev b/tools/dev/Dockerfile-dev
new file mode 100644
index 0000000..d589ba0
--- /dev/null
+++ b/tools/dev/Dockerfile-dev
@@ -0,0 +1,66 @@
+# Dockerfile for ODTN container
+
+# First stage is the build environment
+FROM picoded/ubuntu-openjdk-8-jdk as builder
+MAINTAINER Boyuan Yan <boyuan@opennetworking.org>
+
+# Set the environment variables
+ENV HOME /root
+ENV BUILD_NUMBER docker
+ENV JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF8
+
+# Copy in the source
+COPY onos.tar.gz /src/onos/
+
+# Build ONOS
+# We extract the tar in the build environment to avoid having to put the tar
+# in the runtime environment - this saves a lot of space
+# FIXME - dependence on ONOS_ROOT and git at build time is a hack to work around
+# build problems
+WORKDIR /src/onos
+RUN apt-get update && \
+        DEBIAN_FRONTEND=noninteractive \
+        apt-get install -y zip python git bzip2 build-essential && \
+        export ONOS_ROOT=/src/onos && \
+        mkdir -p /src/tar && \
+        cd /src/tar && \
+        tar -xf /src/onos/onos.tar.gz --strip-components=1 && \
+        rm -rf /src/onos/bazel-* .git
+
+# Second stage is the runtime environment
+FROM adoptopenjdk/openjdk11:x86_64-ubuntu-jdk-11.0.1.13-slim
+
+# Change to /root directory
+RUN     mkdir -p /root/onos
+WORKDIR /root/onos
+
+# Install ONOS
+COPY --from=builder /src/tar/ .
+
+# Configure ONOS to log to stdout
+RUN sed -ibak '/log4j.rootLogger=/s/$/, stdout/' $(ls -d apache-karaf-*)/etc/org.ops4j.pax.logging.cfg
+
+LABEL org.label-schema.name="ONOS" \
+      org.label-schema.description="SDN Controller" \
+      org.label-schema.usage="http://wiki.onosproject.org" \
+      org.label-schema.url="http://onosproject.org" \
+      org.label-scheme.vendor="Open Networking Foundation" \
+      org.label-schema.schema-version="1.0"
+
+# Ports
+# 6653 - OpenFlow
+# 6640 - OVSDB
+# 8181 - GUI
+# 8101 - ONOS CLI
+# 9876 - ONOS intra-cluster communication
+EXPOSE 6653 6640 8181 8101 9876
+
+# Open SSH server
+RUN apt-get update && apt-get install -y openssh-server
+RUN mkdir /var/run/sshd
+RUN echo 'root:rocks' | chpasswd
+EXPOSE 22
+
+# Get ready to run command
+ENTRYPOINT ["./bin/onos-service"]
+CMD ["server"]
diff --git a/tools/test/bin/stc b/tools/test/bin/stc
index 9c5702f..4e4c2d8 100755
--- a/tools/test/bin/stc
+++ b/tools/test/bin/stc
@@ -3,6 +3,20 @@
 #   System Test Coordinator
 #-------------------------------------------------------------------------------
 
+# If specifiy another env init script, load it.
+params=()
+index=0
+for i in $@; do
+    key=`echo $i | awk -F '=' '{print $1}'`
+    if [ "$key" == "-ENV_DEFAULT" ]; then
+	val=`echo $i | awk -F '=' '{print $2}'`
+	source $val
+    else
+	params[$index]=$i
+	let index+=1
+    fi
+done
+
 . $ONOS_ROOT/tools/build/envDefaults
 
 VER=${STC_VERSION:-2.5}
@@ -20,7 +34,7 @@
 
 DEBUG_OPTS="-agentlib:jdwp=transport=dt_socket,address=5005,server=y,suspend=y"
 
-scenario=${1:-smoke}
+scenario=${params[0]:-smoke}
 
 if [ $scenario != "-?" -a $scenario != "-h" -a $scenario != "--help" ]; then
     [ ! -f $scenario ] && scenario=$SCENARIOS/$scenario
@@ -38,4 +52,4 @@
 # Run stc
 [ -z "$stcDebug" ] && DEBUG_OPTS=""
 stcTitle=${stcTitle:-} stcColor=${stcColor:-$interactive} stcDumpLogs=${stcDumpLogs:-$notInteractive} \
-    java $DEBUG_OPTS -jar $JAR $scenario "$@"
+    java $DEBUG_OPTS -jar $JAR $scenario "${params[*]}"
diff --git a/tools/test/scenarios/bin/execute-tapi-delete-call.py b/tools/test/scenarios/bin/execute-tapi-delete-call.py
old mode 100644
new mode 100755
diff --git a/tools/test/scenarios/bin/execute-tapi-post-call.py b/tools/test/scenarios/bin/execute-tapi-post-call.py
index 59f535f..f6d419a 100755
--- a/tools/test/scenarios/bin/execute-tapi-post-call.py
+++ b/tools/test/scenarios/bin/execute-tapi-post-call.py
@@ -6,7 +6,7 @@
 
 if len(sys.argv) < 4:
     print "usage: execute-tapi-post-call <onos-node> <context> <empty> [uuid]."
-    print "\t- If <empty> is \"empty\", it measn that it shoudl be no devices, links or ports"
+    print "\t- If <empty> is \"empty\", it measn that it should be no devices, links or ports"
     print "\t- Uuid is optional and defaults to empty"
     print "\t- For example:\n\t\t- line-side connectivity creation: %s\n\t\t- client-side connectivity creation: %s" % \
           ("python execute-tapi-post-call.py 127.0.0.1 tapi-connectivity:create-connectivity-service line-side",
@@ -30,7 +30,13 @@
     print tapi_connection_json
     if not tapi_connection_json["tapi-connectivity:output"] and empty != "empty":
        print "No connection was established"
-       sys.exit(1)
+       sys.exit(0)
+    if empty == "empty":
+        if not tapi_connection_json["tapi-connectivity:output"]:
+            sys.exit(0)
+        else:
+            print "There exist some connectivities!!!"
+            sys.exit(1)
     if uuid == "":
         # verify empty connection
         print tapi_connection_json
diff --git a/tools/test/scenarios/net-odtn-presmoke.xml b/tools/test/scenarios/net-odtn-presmoke.xml
new file mode 100644
index 0000000..dbff113
--- /dev/null
+++ b/tools/test/scenarios/net-odtn-presmoke.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<!--
+  ~ Copyright 2018-present Open Networking Foundation
+  ~
+  ~ 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-odtn-presmoke" description="Start ODTN docker containers and set env variables">
+  <group name="ODTN-Net-Prepare">
+    <step name="ODTN-Net-Prepare.clean-docker" exec="bash ${ONOS_SCENARIOS}/odtn/destroyOdtnCell.sh"/>
+    <step name="ODTN-Net-Prepare.build-docker-img" exec="bash ${ONOS_SCENARIOS}/odtn/buildOdtnDocker.sh" requires="ODTN-Net-Prepare.clean-docker"/>
+    <step name="ODTN-Net-Prepare.create-docker-containers" requires="ODTN-Net-Prepare.build-docker-img" exec="source ${ONOS_SCENARIOS}/odtn/createOdtnCell.sh"/>
+  </group>
+</scenario>
diff --git a/tools/test/scenarios/net-odtn-restconf.xml b/tools/test/scenarios/net-odtn-restconf.xml
index 93d2095..571bc0b 100644
--- a/tools/test/scenarios/net-odtn-restconf.xml
+++ b/tools/test/scenarios/net-odtn-restconf.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0"?>
 <!--
   ~ Copyright 2015-present Open Networking Foundation
   ~
@@ -13,42 +14,35 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<scenario name="net-odtn-restconf"
-          description="ODTN RESTCONF API test">
-    <group name="Net-ODTN-Restconf">
-
-        <!-- Verify the correct topology is present -->
-
-        <step name="Net-ODTN-Restconf.Tapi-context"
-              exec="execute-tapi-context-get-call.py ${OC1} empty"/>
-
-        <!-- Verify empty connectivity service -->
-
-        <step name="Net-ODTN-Restconf.Tapi-connectivity" requires="Net-ODTN-Restconf.Tapi-context"
-              exec="execute-tapi-post-call.py ${OC1} tapi-connectivity:get-connectivity-service-list empty"/>
-
-        <!-- Push the connectivity service request -->
-
-        <!--<step name="ODTN-Net-Setup.Tapi-connectivity" requires="ODTN-Net-Setup.Tapi-context"
-              exec="execute-tapi-post-call.py ${OC1} tapi-connectivity:get-connectivity-service-list true"/>
-
-        <group name="ODTN-Net-Setup.Verify-Logs-3" requires="ODTN-Net-Setup.Tapi-connectivity">
-            <parallel var="${OC#}">
-                <step name="Check-Logs-3-${#}" exec="onos-check-logs ${OC#}"/>
-            </parallel>
-        </group>
-
-        <step name="ODTN-Net-Setup.Tapi-context" requires="ODTN-Net-Setup.Verify-Logs"
-              exec="execute-tapi-context-get-call.py ${OC1} empty"/>
-        <step name="ODTN-Net-Setup.Tapi-connectivity" requires="ODTN-Net-Setup.Tapi-context"
-              exec="execute-tapi-post-call.py ${OC1} tapi-connectivity:get-connectivity-service-list empty true"/>
-
-        <group name="ODTN-Net-Setup.Verify-Logs-4" requires="ODTN-Net-Setup.Tapi-connectivity">
-            <parallel var="${OC#}">
-                <step name="Check-Logs-4-${#}" exec="onos-check-logs ${OC#}"/>
-            </parallel>
-        </group>-->
-
-
+<scenario name="net-odtn-restconf" description="ODTN RESTCONF API test">
+  <group name="Net-ODTN-Restconf">
+    <!-- Verify the correct topology is present -->
+    <step name="Net-ODTN-Restconf.Tapi-context" exec="execute-tapi-context-get-call.py ${OC1} empty"/>
+    <!-- Verify empty connectivity service -->
+    <step name="Net-ODTN-Restconf.Confirm-conn-empty" requires="Net-ODTN-Restconf.Tapi-context" exec="execute-tapi-post-call.py ${OC1} tapi-connectivity:get-connectivity-service-list empty"/>
+    <!-- Push the line-side connectivity service request -->
+    <group name="Net-ODTN-Restconf.Line-side-test" requires="Net-ODTN-Restconf.Confirm-conn-empty">
+      <step name="Net-ODTN-Restconf.Create-line-side" exec="execute-tapi-post-call.py ${OC1} tapi-connectivity:create-connectivity-service line-side"/>
+      <step name="Net-ODTN-Restconf.Check-line-side" requires="Net-ODTN-Restconf.Create-line-side" exec="${ONOS_SCENARIOS}/odtn/checkUntilSucc.sh 'execute-tapi-post-call.py+${OC1}+tapi-connectivity:get-connectivity-service-list+empty+|+grep+'tapi-connectivity:output'+|+grep+connection-uuid+-o+|+wc+-l' 1" />
+      <step name="Net-ODTN-Restconf.Delete-line-conn" requires="Net-ODTN-Restconf.Check-line-side" exec="execute-tapi-delete-call.py ${OC1} line"/>
+      <step name="Net-ODTN-Restconf.Confirm-conn-empty-2" requires="Net-ODTN-Restconf.Delete-line-conn" exec="execute-tapi-post-call.py ${OC1} tapi-connectivity:get-connectivity-service-list empty"/>
+      <group name="Net-ODTN-Restconf.Verify-Logs" requires="Net-ODTN-Restconf.Confirm-conn-empty-2">
+        <parallel var="${OC#}">
+          <step name="Check-Logs-Restconf-1-${#}" exec="onos-check-logs ${OC#}"/>
+        </parallel>
+      </group>
     </group>
+    <!-- Push the client-side connectivity service request -->
+    <group name="Net-ODTN-Restconf.Client-side-test" requires="Net-ODTN-Restconf.Line-side-test" delay="10" >
+      <step name="Net-ODTN-Restconf.Create-client-side" exec="execute-tapi-post-call.py ${OC1} tapi-connectivity:create-connectivity-service client-side"/>
+      <step name="Net-ODTN-Restconf.Check-client-side" requires="Net-ODTN-Restconf.Create-client-side" exec="${ONOS_SCENARIOS}/odtn/checkUntilSucc.sh 'execute-tapi-post-call.py+${OC1}+tapi-connectivity:get-connectivity-service-list+empty+|+grep+'tapi-connectivity:output'+|+grep+connection-uuid+-o+|+wc+-l' 1" />
+      <step name="Net-ODTN-Restconf.Delete-client-conn" requires="Net-ODTN-Restconf.Check-client-side" exec="execute-tapi-delete-call.py ${OC1} both"/>
+      <step name="Net-ODTN-Restconf.Confirm-conn-empty-3" requires="Net-ODTN-Restconf.Delete-client-conn" exec="execute-tapi-post-call.py ${OC1} tapi-connectivity:get-connectivity-service-list empty"/>
+      <group name="Net-ODTN-Restconf.Verify-Logs-2" requires="Net-ODTN-Restconf.Confirm-conn-empty-3">
+        <parallel var="${OC#}">
+          <step name="Check-Logs-Restconf-2-${#}" exec="onos-check-logs ${OC#}"/>
+        </parallel>
+      </group>
+    </group>
+  </group>
 </scenario>
diff --git a/tools/test/scenarios/net-odtn-smoke.xml b/tools/test/scenarios/net-odtn-smoke.xml
index e49ca73..f1e1f7d 100644
--- a/tools/test/scenarios/net-odtn-smoke.xml
+++ b/tools/test/scenarios/net-odtn-smoke.xml
@@ -14,24 +14,10 @@
   ~ limitations under the License.
   -->
 
-
-<scenario name="net-odtn-smoke"
-          description="ODTN test steps">
-
-    <import file="${ONOS_SCENARIOS}/net-setup-odtn.xml"/>
-
-    <!--TODO check proper topology-->
-    <!--<step name="Net-ODTN-Smoke.Check-Summary"
-          requires="ODTN-Net-Setup.Verify-Logs-2" delay="5"
-          exec="onos-check-summary ${OC1} [0-9]* 4 8 0 112"/>-->
-
-    <import file="${ONOS_SCENARIOS}/net-odtn-restconf.xml"/>
-    <dependency name="Net-ODTN-Restconf" requires="ODTN-Net-Setup"/>
-
-    <import file="${ONOS_SCENARIOS}/net-teardown-odtn.xml"/>
-    <dependency name="Net-Teardown-ODTN" requires="Net-ODTN-Restconf"/>
-
-    <import file="${ONOS_SCENARIOS}/shutdown.xml"/>
-    <dependency name="Shutdown-ONOS" requires="Net-Teardown-ODTN"/>
-
+<scenario name="net-odtn-smoke" description="ODTN test steps">
+  <import file="${ONOS_SCENARIOS}/net-setup-odtn.xml"/>
+  <import file="${ONOS_SCENARIOS}/net-odtn-restconf.xml"/>
+  <dependency name="Net-ODTN-Restconf" requires="ODTN-Net-Setup"/>
+  <import file="${ONOS_SCENARIOS}/net-teardown-odtn.xml"/>
+  <dependency name="Net-Teardown-ODTN" requires="Net-ODTN-Restconf"/>
 </scenario>
diff --git a/tools/test/scenarios/net-setup-odtn.xml b/tools/test/scenarios/net-setup-odtn.xml
index 9b6aa08..8d6f811 100644
--- a/tools/test/scenarios/net-setup-odtn.xml
+++ b/tools/test/scenarios/net-setup-odtn.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0"?>
 <!--
   ~ Copyright 2015-present Open Networking Foundation
   ~
@@ -13,81 +14,58 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-
 <scenario name="net-setup-odtn" description="ODTN network setup steps">
-
-    <group name="ODTN-Net-Setup">
-
-        <!-- Clean -->
-        <step name="ODTN-Net-Setup.Wipe-Out-Data-Before" exec="onos-wipe-out"/>
-
-        <!-- Make sure that there is no data in the system -->
-        <step name="ODTN-Net-Setup.Initial-Summary-Check" requires="~ODTN-Net-Setup.Wipe-Out-Data-Before"
-              exec="onos-check-summary ${OC1} [0-9]* 0 0 0"/>
-
-        <!-- Deactivate unneeded apps -->
-        <group name="ODTN-Net-Setup.Deactivate-Apps" requires="ODTN-Net-Setup.Initial-Summary-Check">
-            <step name="App-Deactivate-fwd"
-                  exec="onos ${OCI} app deactivate org.onosproject.fwd"
-                  requires="ODTN-Net-Setup.Initial-Summary-Check"/>
-            <step name="App-Deactivate-Openflow"
-                  exec="onos ${OCI} app deactivate org.onosproject.openflow"
-                  requires="ODTN-Net-Setup.Initial-Summary-Check"/>
-            <step name="App-Deactivate-Drivers"
-                  exec="onos ${OCI} app deactivate org.onosproject.drivers"
-                  requires="ODTN-Net-Setup.Initial-Summary-Check"/>
-            <step name="App-Deactivate-Mobility"
-                  exec="onos ${OCI} app deactivate org.onosproject.mobility"
-                  requires="ODTN-Net-Setup.Initial-Summary-Check"/>
-            <step name="App-Deactivate-ProxyArp"
-                  exec="onos ${OCI} app deactivate org.onosproject.proxyarp"
-                  requires="ODTN-Net-Setup.Initial-Summary-Check"/>
-            <step name="App-Deactivate-RouteService"
-                  exec="onos ${OCI} app deactivate org.onosproject.route-service"
-                  requires="ODTN-Net-Setup.Initial-Summary-Check"/>
-        </group>
-
-        <!-- Active required apps and yang models-->
-        <group name="ODTN-Net-Setup.Activate-Apps" requires="ODTN-Net-Setup.Deactivate-Apps">
-            <step name="App-Activate-Odtn-Service"
-                  exec="onos ${OCI} app activate org.onosproject.odtn-service"
-                  requires="ODTN-Net-Setup.Deactivate-Apps"/>
-        </group>
-
-        <group name="ODTN-Net-Setup.Verify-Apps" requires="ODTN-Net-Setup.Activate-Apps" delay="40">
-            <parallel var="${OC#}">
-                <step name="Check-Apps-${#}" exec="onos-check-apps ${OC#} optical-model,yang,config,configsync,faultmanagement,
-                netconf,configsync-netconf,gui,drivers,drivers.netconf,drivers.optical,restconf,protocols.restconfserver,
-                odtn-api,drivers.odtn-driver,odtn-service,models.tapi,models.ietf,models.openconfig,models.openconfig-infinera,
-                models.openconfig-odtn includes"
-                      requires="ODTN-Net-Setup.Activate-Apps"/>
-            </parallel>
-        </group>
-
-        <group name="ODTN-Net-Setup.Verify-Logs" requires="ODTN-Net-Setup.Verify-Apps">
-            <parallel var="${OC#}">
-                <step name="Check-Logs-${#}" exec="onos-check-logs ${OC#}"/>
-            </parallel>
-        </group>
-
-        <step name="ODTN-Net-Setup.Tapi-context" requires="ODTN-Net-Setup.Verify-Logs"
-              exec="execute-tapi-context-get-call.py ${OC1} empty"/>
-
-        <group name="ODTN-Net-Setup.Verify-Logs-2" requires="ODTN-Net-Setup.Tapi-context">
-            <parallel var="${OC#}">
-                <step name="Check-Logs-2-${#}" exec="onos-check-logs ${OC#}"/>
-            </parallel>
-        </group>
-
-        <!-- Verify empty connectivity service -->
-
-        <step name="ODTN-Net-Setup.Tapi-connectivity" requires="ODTN-Net-Setup.Tapi-context"
-              exec="execute-tapi-post-call.py ${OC1} tapi-connectivity:get-connectivity-service-list empty"/>
-
-        <!--TODO include check for empty connectivity service-->
-        <!--TODO include 2 or more docker emulators to setup the network for phase 1.0-->
-        <!--TODO push netcfg links between emulated devices -->
-        <!--TODO push emulated links between emulated devices -->
-        <!--TODO check logs -->
+  <group name="ODTN-Net-Setup">
+    <!-- Clean -->
+    <step name="ODTN-Net-Setup.Wipe-Out-Data-Before" exec="onos-wipe-out"/>
+    <!-- Make sure that there is no data in the system -->
+    <step name="ODTN-Net-Setup.Initial-Summary-Check" requires="~ODTN-Net-Setup.Wipe-Out-Data-Before" exec="onos-check-summary ${OC1} [0-9]* 0 0 0"/>
+    <step name="ODTN-Net-Setup.Activate-Apps" exec="onos ${OC1} app activate odtn-service" requires="ODTN-Net-Setup.Initial-Summary-Check" delay="30" />
+    <group name="ODTN-Net-Setup.Verify-Apps" requires="ODTN-Net-Setup.Activate-Apps" delay="30">
+      <parallel var="${OC#}">
+        <step name="Check-Apps-${#}" exec="onos-check-apps ${OC#} optical-model,yang,config,configsync,faultmanagement,netconf,configsync-netconf,drivers,drivers.netconf,drivers.optical,restconf,protocols.restconfserver,odtn-api,drivers.odtn-driver,odtn-service,models.tapi,models.ietf,models.openconfig,models.openconfig-infinera,models.openconfig-odtn includes" requires="ODTN-Net-Setup.Activate-Apps"/>
+      </parallel>
     </group>
+    <group name="ODTN-Net-Setup.Tapi-context" requires="ODTN-Net-Setup.Verify-Apps">
+      <parallel var="${OC#}">
+        <step name="ODTN-Net-Setup.Tapi-context-${#}" exec="${ONOS_SCENARIOS}/odtn/checkUntilSucc.sh ${ONOS_SCENARIOS}/bin/execute-tapi-context-get-call.py+${OC#}+empty"/>
+      </parallel>
+    </group>
+    <!-- Verify empty connectivity service -->
+    <step name="ODTN-Net-Setup.Tapi-connectivity" requires="ODTN-Net-Setup.Tapi-context" exec="${ONOS_SCENARIOS}/odtn/checkUntilSucc.sh ${ONOS_SCENARIOS}/bin/execute-tapi-post-call.py+${OC1}+tapi-connectivity:get-connectivity-service-list+empty"/>
+    <group name="ODTN-Net-Setup.Verify-Logs-1" requires="ODTN-Net-Setup.Tapi-connectivity">
+      <parallel var="${OC#}">
+        <step name="Check-Logs-Odtn-Setup-1-${#}" exec="onos-check-logs ${OC#}"/>
+      </parallel>
+    </group>
+    <!-- include 2 or more docker emulators to setup the network for phase 1.0-->
+    <group name="ODTN-Net-Setup.Init-network" requires="ODTN-Net-Setup.Verify-Logs-1">
+      <step name="ODTN-Net-Setup.Start-emulators" exec="docker-compose -f /home/sdn/emulator/docker-compose.yaml up -d"/>
+      <step name="ODTN-Net-Setup.Generate-cfg-files" requires="ODTN-Net-Setup.Start-emulators" exec="${ONOS_SCENARIOS}/odtn/createNetCfg.sh"/>
+      <step name="ODTN-Net-Setup.Put-nodes" requires="ODTN-Net-Setup.Generate-cfg-files" exec="onos-netcfg ${OC1} /tmp/odtn/openconfig-devices.json"/>
+      <group name="ODTN-Net-Setup.Wait-nodes" requires="ODTN-Net-Setup.Put-nodes">
+        <parallel var="${OC#}">
+          <step name="ODTN-Net-Setup.Wait-node-${#}" exec="${ONOS_SCENARIOS}/odtn/checkNetInit.sh device ${OC#}"/>
+          <step name="ODTN-Net-Setup.Wait-port-${#}" exec="${ONOS_SCENARIOS}/odtn/checkNetInit.sh port ${OC#}" requires="ODTN-Net-Setup.Wait-node-${#}"/>
+        </parallel>
+      </group>
+      <group name="ODTN-Net-Setup.Verify-Logs-2" requires="ODTN-Net-Setup.Wait-nodes">
+        <parallel var="${OC#}">
+          <step name="Check-Logs-Odtn-Setup-2-${#}" exec="onos-check-logs ${OC#}"/>
+        </parallel>
+      </group>
+      <step name="ODTN-Net-Setup.Put-links" requires="ODTN-Net-Setup.Verify-Logs-2" exec="onos-netcfg ${OC1} /tmp/odtn/openconfig-device-link.json"/>
+      <group name="ODTN-Net-Setup.Wait-links" requires="ODTN-Net-Setup.Put-links" delay="30">
+        <parallel var="${OC#}">
+          <step name="ODTN-Net-Setup.Wait-link-${#}" exec="${ONOS_SCENARIOS}/odtn/checkNetInit.sh link ${OC#}"/>
+        </parallel>
+      </group>
+    </group>
+    <!-- check logs to verify -->
+    <group name="ODTN-Net-Setup.Verify-Logs-3" requires="ODTN-Net-Setup.Wait-links">
+      <parallel var="${OC#}">
+        <step name="Check-Logs-Odtn-Setup-3-${#}" exec="onos-check-logs ${OC#}"/>
+      </parallel>
+    </group>
+  </group>
 </scenario>
diff --git a/tools/test/scenarios/net-teardown-odtn.xml b/tools/test/scenarios/net-teardown-odtn.xml
index be063c1..be78544 100644
--- a/tools/test/scenarios/net-teardown-odtn.xml
+++ b/tools/test/scenarios/net-teardown-odtn.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0"?>
 <!--
   ~ Copyright 2015-present Open Networking Foundation
   ~
@@ -14,11 +15,8 @@
   ~ limitations under the License.
   -->
 <scenario name="net-teardown-odtn" description="Network teardown steps">
-    <group name="Net-Teardown-ODTN">
-        <!-- TODO remove docker simulators docker stop $(docker ps -aq) -->
-        <group name="ODTN-Net-Teardown.Deactivate-Apps-2">
-            <step name="App-Dectivate-Odtn-Service"
-                  exec="onos ${OCI} app deactivate org.onosproject.odtn-service"/>
-        </group>
-    </group>
-</scenario>
\ No newline at end of file
+  <group name="Net-Teardown-ODTN">
+    <step name="App-Dectivate-Odtn-Service" exec="onos ${OCI} app deactivate org.onosproject.odtn-service"/>
+    <step name="Remove-onos-images-stop-emulators" requires="App-Dectivate-Odtn-Service" exec="${ONOS_SCENARIOS}/odtn/destroyOdtnCell.sh"/>
+  </group>
+</scenario>
diff --git a/tools/test/scenarios/odtn/README.md b/tools/test/scenarios/odtn/README.md
new file mode 100644
index 0000000..8a6eae6
--- /dev/null
+++ b/tools/test/scenarios/odtn/README.md
@@ -0,0 +1,36 @@
+## Description
+
+This directory contains several Shell scripts for ODTN project testing in STC environment.
+The normal steps of ODTN testing are listed:
+
+#### 1. `stc net-odtn-presmoke`
+This command completes preparation for testing, including latest onos image build, and onos/atomix cluster containers startup. Also, because of dynamic IP Address for containers, some related environment variables are stored in /tmp/odtn/OCvar.sh. All subsequent stc command should source this file as default environment. An example of this file is:
+
+```shell
+#!/bin/bash
+export OC1=172.17.0.5
+export OC2=172.17.0.6
+export OC3=172.17.0.7
+export OCI=172.17.0.5
+export ONOS_INSTANCES="172.17.0.5 172.17.0.6 172.17.0.7"
+export ONOS_USER=root
+export ONOS_INSTALL_DIR=/root/onos/apache-karaf-4.2.3/data
+```
+
+Besides, the access for each onos container are very easy (`source /tmp/odtn/OCvar` firstly):
+* If you want to login ONOS CLI directly, please type `onos $OC1/2/3`.
+* If you want to login ONOS container, please type `ssh root@OC1/2/3`.
+
+#### 2. `stc -ENV_DEFAULT=/tmp/odtn/OCvar.sh net-odtn-smoke`
+
+This command contains thress substeps in order, you can use these steps one by one:
+* `stc -ENV_DEFAULT=/tmp/odtn/OCvar.sh net-setup-odtn`
+In this step, `odtn-service` and related multiple apps are installed and checked. Then emulator containers are started, whose topology is pushed into onos/atomix cluster via `onos-netcfg`.
+
+This command invokes script `CheckNetInit.sh`, which need file "~/emulator/net-summary.json" to load number of device/port/link.
+
+* `stc -ENV_DEFAULT=/tmp/odtn/OCvar.sh net-odtn-restconf`
+In this step, line-side and client-side connectivity creation and deletion are tested.
+
+* `stc -ENV_DEFAULT=/tmp/odtn/OCvar.sh net-teardown-odtn`
+In this step, all onos/atomix/emulator containers are stopped and removed, and onos images are removed.
diff --git a/tools/test/scenarios/odtn/buildOdtnDocker.sh b/tools/test/scenarios/odtn/buildOdtnDocker.sh
new file mode 100755
index 0000000..1844714
--- /dev/null
+++ b/tools/test/scenarios/odtn/buildOdtnDocker.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+# This script is used to build onos by using bazel, and create related docker image from ${ONOS_ROOT}/tools/dev/Dockerfile-dev
+
+# Initialize the environment
+shopt -s expand_aliases
+export PATH="$PATH:$HOME/bin:onos/bin"
+export ONOS_ROOT=~/onos
+source ${ONOS_ROOT}/tools/dev/bash_profile
+
+# Compile and Package ONOS
+cd ${ONOS_ROOT}
+# ob is replaced by bazel build onos
+bazel build onos
+rtn=$?
+if [[ ${rtn} -ne 0 ]]
+then
+    exit ${rtn}
+fi
+# Re-deploy ONOS
+[ -f tools/dev/onos.tar.gz ] && rm -f tools/dev/onos.tar.gz
+cp bazel-bin/onos.tar.gz tools/dev/
+# Build ONOS's docker image, and start ONOS cluster through docker
+cd tools/dev/
+docker build -t onos -f Dockerfile-dev .
+rm -f onos.tar.gz
+exit $?
diff --git a/tools/test/scenarios/odtn/checkNetInit.sh b/tools/test/scenarios/odtn/checkNetInit.sh
new file mode 100755
index 0000000..792a8d7
--- /dev/null
+++ b/tools/test/scenarios/odtn/checkNetInit.sh
@@ -0,0 +1,86 @@
+#!/bin/bash
+
+# Two input parameters:
+# $1 - one of {device, port, link}, specify what needs to be checked.
+# $2 - IP address of ONOS instance.
+
+line_num=`cat ~/emulator/net-summary.json | wc -l`
+if [[ "$line_num" != "1" ]]; then
+    echo "JSON file should have only 1 line."
+    exit 1
+fi
+
+# Extract specific value from returned json string under onos command "odtn-show-tapi-context"
+function get_json_value()
+{
+    local json=$1
+    local key=$2
+
+    if [[ -z "$3" ]]; then
+    local num=1
+    else
+    local num=$3
+    fi
+
+    local value=$(echo "${json}" | awk -F"[,:}]" '{for(i=1;i<=NF;i++){if($i~/'${key}'\042/){print $(i+1)}}}' | tr -d '"' | sed -n ${num}p)
+
+    return ${value}
+}
+
+tried=0
+case "$1" in
+    "device" )
+        get_json_value $( cat ~/emulator/net-summary.json) device_num
+        device_num=$?
+        num_in_topo=`onos $2 devices | wc -l`
+        num_in_tapi=`onos $2 odtn-show-tapi-context | grep "<node>" | wc -l`
+        while [[ "$num_in_topo" != "$device_num" || "$num_in_tapi" != "$device_num" ]]
+        do
+            echo "On ONOS $2, current device num in topo:$num_in_topo, num in tapi:$num_in_tapi, expected $device_num. Waiting..."
+            sleep 10
+            num_in_topo=`onos $2 devices | wc -l`
+                num_in_tapi=`onos $2 odtn-show-tapi-context | grep "<node>" | wc -l`
+            let "tried=tried+1"
+            if [[ "$tried" == "10" ]]; then
+                exit 99
+            fi
+        done
+        ;;
+    "port" )
+        get_json_value $( cat ~/emulator/net-summary.json) port_num
+        port_num=$?
+        get_json_value $( cat ~/emulator/net-summary.json) device_num
+        device_num=$?
+        num_in_tapi=`onos $2 odtn-show-tapi-context | grep "<owned-node-edge-point>" | wc -l`
+        num_in_topo=`onos $2 ports | wc -l`
+        num_in_topo=$[num_in_topo-device_num]
+        while [[ "$num_in_topo" != "$port_num" || "$num_in_tapi" != "$port_num" ]]
+            do
+            echo "On ONOS $2, current port num in topo: $num_in_topo, num in tapi: $num_in_tapi, expected $port_num. Waiting..."
+                    sleep 10
+            num_in_topo=`onos $2 ports | wc -l`
+            num_in_topo=$[num_in_topo-device_num]
+            num_in_tapi=`onos $2 odtn-show-tapi-context | grep "<owned-node-edge-point>" | wc -l`
+            let "tried=tried+1"
+            if [[ "$tried" == "10" ]]; then
+                exit 99
+            fi
+            done
+            ;;
+    "link" )
+        get_json_value $( cat ~/emulator/net-summary.json) link_num
+        link_num=$?
+        num_in_topo=`onos $2 links | wc -l`
+        num_in_tapi=`onos $2 odtn-show-tapi-context | grep "<link>" | wc -l`
+            while [[ "$num_in_topo" != "$link_num" || "$num_in_tapi" != "$link_num" ]]
+            do
+                    echo "On ONOS $2, current link num: $num_in_topo, expected $link_num. Waiting..."
+            sleep 10
+                    num_in_topo=`onos $2 links | wc -l`
+            num_in_tapi=`onos $2 odtn-show-tapi-context | grep "<link>" | wc -l`
+            let "tried=tried+1"
+            if [[ "$tried" == "10" ]]; then
+                exit 99
+            fi
+            done
+esac
diff --git a/tools/test/scenarios/odtn/checkUntilSucc.sh b/tools/test/scenarios/odtn/checkUntilSucc.sh
new file mode 100755
index 0000000..808ac0e
--- /dev/null
+++ b/tools/test/scenarios/odtn/checkUntilSucc.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+# This script is used to execute some checking commands in period to confirm whether specific requirement is satisfied.
+# $1 - the command to be executed in this script, whose parameter splitter is +, but ont space. This command could use |, &&, || to concatenate multiple shell commands.
+# $2 - Optional. If exists, it means the output (Note: not returned value) of $1 should equals $2.
+
+cmd=${1//'+'/' '}
+if [ $# == 1 ]; then
+    for i in {1..60}; do
+        eval ${cmd}
+        rtn=$?
+        if [[ ${rtn} -ne 0 ]]
+        then
+            echo "$i-th execution returns $rtn"
+            sleep 3
+        else
+            exit 0
+        fi
+    done
+elif [ $# == 2 ]; then
+    for i in {1..60}; do
+        out=`eval ${cmd}`
+        rtn=$?
+        if [[ ${rtn} -ne 0 || "$out" != $2 ]]; then
+            echo "$i-th execution fails"
+            sleep 3
+        else
+            exit 0
+        fi
+    done
+fi
diff --git a/tools/test/scenarios/odtn/createNetCfg.sh b/tools/test/scenarios/odtn/createNetCfg.sh
new file mode 100755
index 0000000..9bbd456
--- /dev/null
+++ b/tools/test/scenarios/odtn/createNetCfg.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+# Get first IPv4 Address on local machine, even the machine has lots of NICs.
+localIP=`ifconfig -a|grep inet|grep -v 127.0.0.1|grep -v inet6|awk '{print $2}'|tr -d "addr:" | head -n1`
+mkdir /tmp/odtn
+# Replace IP address in openconfig json files with real ones.
+cat ${ONOS_ROOT}/apps/odtn/api/src/test/resources/openconfig-devices.json | sed "s/127.0.0.1/${localIP}/g" > /tmp/odtn/openconfig-devices.json
+cat ${ONOS_ROOT}/apps/odtn/api/src/test/resources/openconfig-device-link.json | sed "s/127.0.0.1/${localIP}/g" > /tmp/odtn/openconfig-device-link.json
+sleep 30
diff --git a/tools/test/scenarios/odtn/createOdtnCell.sh b/tools/test/scenarios/odtn/createOdtnCell.sh
new file mode 100755
index 0000000..91f9197
--- /dev/null
+++ b/tools/test/scenarios/odtn/createOdtnCell.sh
@@ -0,0 +1,85 @@
+#!/bin/bash
+
+# Create onos and atomix containers from related images.
+
+# Initialize the environment
+shopt -s expand_aliases
+export PATH="$PATH:$HOME/bin:onos/bin"
+export ONOS_ROOT=~/onos
+source ${ONOS_ROOT}/tools/dev/bash_profile
+KARAF_VERSION=`cat ${ONOS_ROOT}/tools/build/envDefaults | grep KARAF_VERSION= | awk -F '=' '{print $2}'`
+
+# Start ONOS cluster through docker
+cd ~/onos/tools/tutorials/vm
+SSH_KEY=$(cut -d\  -f2 ~/.ssh/id_rsa.pub)
+FULL_SSH_KEY=$(cat ~/.ssh/id_rsa.pub)
+echo "The public key in local host is: $SSH_KEY"
+
+# Create Atomix cluster using Atomix docker image
+ATOMIX_IMAGE=atomix/atomix:3.1.5
+for i in {1..3}; do
+    echo "Setting up atomix-$i..."
+    docker container run --detach --name atomix-$i --hostname atomix-$i \
+        --restart=always -v /home/sdn/onos/tools/tutorials/vm/config:/atomix/config $ATOMIX_IMAGE \
+        --config /atomix/config/atomix-$i.conf
+done
+wait
+
+# Create and start  ONOS cluster using ONOS docker image
+ONOS_IMAGE=onos:latest
+for i in {1..3}; do
+    echo "Setting up onos-$i..."
+    docker container run --detach --name onos-$i --hostname onos-$i --restart=always $ONOS_IMAGE
+    docker exec -i onos-$i /bin/bash -c "mkdir config; cat > config/cluster.json" < $ONOS_ROOT/tools/tutorials/vm/config/cluster-$i.json
+    docker exec -i onos-$i /bin/bash -c "touch /root/onos/apache-karaf-${KARAF_VERSION}/etc/keys.properties"
+    docker exec -i onos-$i /bin/bash -c "echo 'sdn=$SSH_KEY,_g_:admingroup' >> /root/onos/apache-karaf-${KARAF_VERSION}/etc/keys.properties"
+    docker exec -i onos-$i /bin/bash -c "/root/onos/bin/onos-user-password onos rocks"
+    docker exec -i onos-$i /bin/bash -c "ssh-keygen -f /root/.ssh/id_rsa -t rsa -N ''"
+    docker exec -i onos-$i /bin/bash -c "/etc/init.d/ssh start"
+    docker exec -i onos-$i /bin/bash -c "echo '$FULL_SSH_KEY' >> /root/.ssh/authorized_keys"
+done
+
+# Start onos and atomix docker containers
+function waitForStart {
+    sleep 5
+    for i in {1..3}; do
+        echo "Waiting for onos-$i startup..."
+        ip=$(docker container inspect onos-$i | grep \"IPAddress | cut -d: -f2 | sort -u | tr -d '", ')
+        echo "IP is: $ip"
+    for t in {1..60}; do
+        echo "$t-th times curl request"
+            curl --fail -sS http://$ip:8181/onos/v1/applications --user "onos:rocks" 1>/dev/null 2>&1 && break;
+            sleep 1;
+        done
+    echo
+        onos $ip summary >/dev/null 2>&1
+    done
+}
+
+# Extract the IP addresses of the ONOS nodes
+export OC1=$(docker container inspect onos-1 | grep \"IPAddress | cut -d: -f2 | sort -u | tr -d '", ')
+export OC2=$(docker container inspect onos-2 | grep \"IPAddress | cut -d: -f2 | sort -u | tr -d '", ')
+export OC3=$(docker container inspect onos-3 | grep \"IPAddress | cut -d: -f2 | sort -u | tr -d '", ')
+export ONOS_INSTANCES="\"$OC1 $OC2 $OC3\""
+
+waitForStart
+
+# remove known hosts
+ssh-keygen -R $OC1
+ssh-keygen -R $OC2
+ssh-keygen -R $OC3
+# add to known-hosts list
+ssh-keyscan $OC1 >> ~/.ssh/known_hosts
+ssh-keyscan $OC2 >> ~/.ssh/known_hosts
+ssh-keyscan $OC3 >> ~/.ssh/known_hosts
+
+echo "#!/bin/bash" > /tmp/odtn/OCvar.sh
+echo "export OC1=$OC1" >> /tmp/odtn/OCvar.sh
+echo "export OC2=$OC2" >> /tmp/odtn/OCvar.sh
+echo "export OC3=$OC3" >> /tmp/odtn/OCvar.sh
+echo "export OCI=$OC1" >> /tmp/odtn/OCvar.sh
+echo "export ONOS_INSTANCES=$ONOS_INSTANCES" >> /tmp/odtn/OCvar.sh
+echo "export ONOS_USER=root" >> /tmp/odtn/OCvar.sh
+echo "export ONOS_INSTALL_DIR=/root/onos/apache-karaf-${KARAF_VERSION}/data" >> /tmp/odtn/OCvar.sh
+# sleep to wait onos instances start up
+sleep 20
diff --git a/tools/test/scenarios/odtn/destroyOdtnCell.sh b/tools/test/scenarios/odtn/destroyOdtnCell.sh
new file mode 100755
index 0000000..edb640d
--- /dev/null
+++ b/tools/test/scenarios/odtn/destroyOdtnCell.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+# remove existed onos and atomix containers and images, stop emulator containers
+containers=(`docker ps -a | grep -E 'onos-|atomix-|emulator' | awk '{print $1}'`)
+if [[ ${#containers} != 0 ]]; then
+    for var in  ${containers[*]}; do
+        docker stop ${var} &
+    done
+    wait
+else
+    echo "There is no container existed."
+fi
+if [[ $# != 1 || "$1" != "stop-docker" ]]; then
+    if [[ ${#containers} != 0 ]]; then
+        for var in ${containers[*]}; do
+            docker rm ${var} &
+        done
+        wait
+    fi
+    images=(`docker images | grep -e onos -e none -e "<none>" | awk '{print $3}'`)
+    if [[ ${#images} != 0 ]]; then
+        for var in ${images[*]}; do
+            docker rmi ${var} &
+        done
+        wait
+    else
+        echo "There is no onos/atomix docker image existed."
+    fi
+else
+    echo "There is no container and image to be removed."
+fi
diff --git a/tools/test/scenarios/stop-docker.xml b/tools/test/scenarios/stop-docker.xml
new file mode 100644
index 0000000..fc95cc6
--- /dev/null
+++ b/tools/test/scenarios/stop-docker.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<!--
+  ~ Copyright 2015-present Open Networking Foundation
+  ~
+  ~ 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="Stop-docker" description="Stop all docker containers with prefix onos- atomix- emulator-">
+    <step name="Stop-docker.stop-all" exec="${ONOS_SCENARIOS}/odtn/destroyOdtnCell.sh stop-docker"/>
+</scenario>