[ONOS-7876] Initial STC implementation for ODTN

Change-Id: I51a22348cc73c576c5d10551e84ca8ac2f2a2040
diff --git a/apps/odtn/api/src/main/java/org/onosproject/odtn/utils/tapi/TapiObjectHandler.java b/apps/odtn/api/src/main/java/org/onosproject/odtn/utils/tapi/TapiObjectHandler.java
index a2a5572..15208a2 100644
--- a/apps/odtn/api/src/main/java/org/onosproject/odtn/utils/tapi/TapiObjectHandler.java
+++ b/apps/odtn/api/src/main/java/org/onosproject/odtn/utils/tapi/TapiObjectHandler.java
@@ -226,7 +226,8 @@
             try {
                 dcs.createNode(rid, node);
             } catch (FailedException e) {
-                log.warn("Failed to add resource", e);
+                    log.warn("Failed to add resource {}", rid);
+                    log.debug("Exception", e);
             }
         }
     }
diff --git a/tools/test/scenarios/bin/execute-tapi-context-get-call.py b/tools/test/scenarios/bin/execute-tapi-context-get-call.py
new file mode 100755
index 0000000..95cff90
--- /dev/null
+++ b/tools/test/scenarios/bin/execute-tapi-context-get-call.py
@@ -0,0 +1,43 @@
+#! /usr/bin/env python
+
+import requests
+import sys
+import tapiHelper
+
+from requests.auth import HTTPBasicAuth
+
+if len(sys.argv) < 3:
+    print "usage: execute-tapi-context-get-call onos-node state"
+    sys.exit(1)
+
+node = sys.argv[1]
+state = sys.argv[2] #if empty tapi context must be empty, if full it needs to contain all devices and ports
+
+if state != "empty" and len(sys.argv) == 3:
+    print "usage: execute-tapi-context-get-call onos-node full devices links ports"
+    sys.exit(1)
+
+request = 'http://' + node + ':8181/onos/restconf/data/tapi-common:context'
+tapiContext = tapiHelper.get_context(request)
+
+if state == "empty":
+    uuid = tapiContext['tapi-common:context']['tapi-topology:topology-context']['topology'][0]['uuid']
+    if uuid == "":
+        print "empty uuid"
+        sys.exit(1)
+    print "@stc tapi topology uuid=" + uuid
+    sys.exit(0)
+
+if state == "full":
+    devices = sys.argv[3]
+    links = sys.argv[4]
+    ports = sys.argv[5]
+    #TODO parse reply for number of devices, links and ports
+    print "Parsing for given topology not yet implemented"
+    sys.exit(0)
+
+sys.exit(1)
+
+
+
+
diff --git a/tools/test/scenarios/bin/execute-tapi-post-call.py b/tools/test/scenarios/bin/execute-tapi-post-call.py
new file mode 100755
index 0000000..031e276
--- /dev/null
+++ b/tools/test/scenarios/bin/execute-tapi-post-call.py
@@ -0,0 +1,46 @@
+#! /usr/bin/env python
+
+import requests
+import sys
+import tapiHelper
+
+from requests.auth import HTTPBasicAuth
+
+if len(sys.argv) < 4:
+    print "usage: execute-tapi-post-call onos-node context empty uuid. Uuid is optional and defaults to empty"
+    sys.exit(1)
+
+node = sys.argv[1]
+context = sys.argv[2]
+empty = sys.argv[3]
+
+if len(sys.argv) == 4:
+    uuid = ""
+else:
+    uuid = sys.argv[4]
+
+if "get-connectivity-service-list" in context:
+    connectivity_request = 'http://' + node + ':8181/onos/restconf/operations/' + context
+    tapi_connection = tapiHelper.get_connection(connectivity_request, uuid)
+    tapi_connection_json = tapi_connection.json()
+    print tapi_connection_json
+    if not tapi_connection_json["tapi-connectivity:output"] and empty != "empty":
+       print "No connection was established"
+       sys.exit(1)
+    #TODO verify empty connection if uuid is empty
+    #TODO verify correct connection if uuid is not empty
+    sys.exit(0)
+
+if "create-connectivity-service" in context:
+    context_request = 'http://' + node + ':8181/onos/restconf/data/tapi-common:context'
+    connectivity_request = 'http://' + node + ':8181/onos/restconf/operations/' + context
+    tapi_connection = tapiHelper.create_connection(context_request, connectivity_request)
+    print context
+    print tapi_connection.json()
+    sys.exit(0)
+
+sys.exit(1)
+
+
+
+
diff --git a/tools/test/scenarios/bin/tapiHelper.py b/tools/test/scenarios/bin/tapiHelper.py
new file mode 100755
index 0000000..74714d0
--- /dev/null
+++ b/tools/test/scenarios/bin/tapiHelper.py
@@ -0,0 +1,115 @@
+#!/usr/bin/python3
+
+import requests
+import json
+import itertools
+
+#
+# Creates connectivity json
+#
+def tapi_input(sip_uuids):
+    create_input = {
+              "tapi-connectivity:input": {
+                "end-point" : [
+                  {
+                    "local-id": sip_uuids[0],
+                    "service-interface-point": {
+                        "service-interface-point-uuid" : sip_uuids[0]
+                    }
+                  }
+                ,
+                  {
+                    "local-id": sip_uuids[1],
+                    "service-interface-point": {
+                        "service-interface-point-uuid" : sip_uuids[1]
+                    }
+                 }
+                ]
+              }
+            }
+    return create_input
+
+#
+# Obtains TAPI context through restconf
+#
+def get_context(url_context):
+    resp = requests.get(url_context, auth=('onos', 'rocks'))
+    if resp.status_code != 200:
+       raise Exception('GET {}'.format(resp.status_code))
+    return resp.json()
+
+#
+# Requests a connectivity service
+#
+def request_connection(url_connectivity, context):
+    # All Context SIPs
+    sips = context["tapi-common:context"]["service-interface-point"]
+
+    # Sorted Photonic Media SIPs. filter is an iterable
+    esips = list(filter(is_dsr_media, sorted(sips, key=lambda sip: sip["name"][0]["value"])))
+    endpoints = [esips[0], esips[-1]]
+    sip_uuids = []
+    for sip in endpoints:
+        sip_uuids.append(sip["uuid"])
+    for uuid in sip_uuids:
+        print(uuid)
+
+    create_input_json = json.dumps(tapi_input(sip_uuids))
+    print (create_input_json)
+    headers = {'Content-type': 'application/json'}
+    resp = requests.post(url_connectivity, data=create_input_json, headers=headers,  auth=('onos', 'rocks'))
+    if resp.status_code != 200:
+        raise Exception('POST {}'.format(resp.status_code))
+    return resp
+
+#
+# Filter method used to keep only SIPs that are photonic_media
+#
+def is_photonic_media(sip):
+    return sip["layer-protocol-name"]=="PHOTONIC_MEDIA"
+
+#
+# Filter method used to keep only SIPs that are DSR
+#
+def is_dsr_media(sip):
+    return sip["layer-protocol-name"]=="DSR"
+
+#
+# Processes the topology to verify the correctness
+#
+def process_topology():
+   # TODO use method to parse topology
+   # Getting the Topology
+   # topology = context["tapi-common:context"]["tapi-topology:topology-context"]["topology"][0]
+   # nodes = topology["node"];
+   # links = topology["link"];
+   noop
+
+#
+# Creates a connection first getting the context, parsing for SIPS and then issuing the request.
+#
+def create_connection(url_context, url_connectivity):
+    context = get_context(url_context)
+    return request_connection(url_connectivity, context)
+
+#
+# Obtains existing connectivity services
+#
+def get_connection(url_connectivity, uuid):
+    if(uuid == ""):
+        json = '{}'
+    else:
+        #TODO use uuid to retrieve given topo
+        print "Not Yet implemented"
+        json = '{}'
+    headers = {'Content-type': 'application/json'}
+    resp = requests.post(url_connectivity, data=json, headers=headers,  auth=('onos', 'rocks'))
+    if resp.status_code != 200:
+            raise Exception('POST {}'.format(resp.status_code))
+    return resp
+
+
+
+
+
+
diff --git a/tools/test/scenarios/net-odtn-restconf.xml b/tools/test/scenarios/net-odtn-restconf.xml
new file mode 100644
index 0000000..93d2095
--- /dev/null
+++ b/tools/test/scenarios/net-odtn-restconf.xml
@@ -0,0 +1,54 @@
+<!--
+  ~ 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="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>-->
+
+
+    </group>
+</scenario>
diff --git a/tools/test/scenarios/net-odtn-smoke.xml b/tools/test/scenarios/net-odtn-smoke.xml
new file mode 100644
index 0000000..e49ca73
--- /dev/null
+++ b/tools/test/scenarios/net-odtn-smoke.xml
@@ -0,0 +1,37 @@
+<!--
+  ~ 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-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>
diff --git a/tools/test/scenarios/net-setup-odtn.xml b/tools/test/scenarios/net-setup-odtn.xml
new file mode 100644
index 0000000..78987a2
--- /dev/null
+++ b/tools/test/scenarios/net-setup-odtn.xml
@@ -0,0 +1,93 @@
+<!--
+  ~ 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="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,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>
+</scenario>
diff --git a/tools/test/scenarios/net-teardown-odtn.xml b/tools/test/scenarios/net-teardown-odtn.xml
new file mode 100644
index 0000000..be063c1
--- /dev/null
+++ b/tools/test/scenarios/net-teardown-odtn.xml
@@ -0,0 +1,24 @@
+<!--
+  ~ 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="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
diff --git a/tools/test/scenarios/shutdown.xml b/tools/test/scenarios/shutdown.xml
index 8ff43c5..f493da4 100644
--- a/tools/test/scenarios/shutdown.xml
+++ b/tools/test/scenarios/shutdown.xml
@@ -19,7 +19,7 @@
             <step name="Stop-Service-${#}" exec="onos-service ${OC#} stop"/>
             <step name="Wait-for-Stop-${#}" exec="onos-wait-for-stop ${OC#}"
                   requires="~Stop-Service-${#}"/>
-            <step name="Check-Logs-${#}" exec="onos-check-logs ${OC#}"
+            <step name="Shutdown-ONOS.Check-Logs-${#}" exec="onos-check-logs ${OC#}"
                   requires="~Wait-for-Stop-${#}"/>
         </parallel>
     </group>