--- /dev/null
+"""This module contains single a function for normalizing JSON strings."""
+# Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Eclipse Public License v1.0 which accompanies this distribution,
+# and is available at http://www.eclipse.org/legal/epl-v10.html
+
+__author__ = "Vratko Polak"
+__copyright__ = "Copyright(c) 2015, Cisco Systems, Inc."
+__license__ = "Eclipse Public License v1.0"
+__email__ = "vrpolak@cisco.com"
+
+try:
+ import simplejson as _json
+except ImportError: # Python2.7 calls it json.
+ import json as _json
+from hsfl import Hsfl as _Hsfl
+from hsfod import Hsfod as _Hsfod
+
+
+def _hsfl_array(s_and_end, scan_once, **kwargs):
+ """Scan JSON array as usual, but return hsfl instead of list."""
+ values, end = _json.decoder.JSONArray(s_and_end, scan_once, **kwargs)
+ return _Hsfl(values), end
+
+
+class _Decoder(_json.JSONDecoder):
+ """Private class to act as customized JSON decoder.
+
+ Based on: http://stackoverflow.com/questions/10885238/
+ python-change-list-type-for-json-decoding"""
+ def __init__(self, **kwargs):
+ """Initialize decoder with special array implementation."""
+ _json.JSONDecoder.__init__(self, **kwargs)
+ # Use the custom JSONArray
+ self.parse_array = _hsfl_array
+ # Use the python implemenation of the scanner
+ self.scan_once = _json.scanner.py_make_scanner(self)
+
+
+def hsf_json(text): # pylint likes lowercase, Robot shall understand Hsf_Json
+ """Return sorted indented JSON string, or an error message string."""
+ try:
+ object_decoded = _json.loads(text, cls=_Decoder, object_hook=_Hsfod)
+ except ValueError as err:
+ return str(err) + '\n' + text
+ pretty_json = _json.dumps(object_decoded, separators=(',', ': '), indent=1)
+ return pretty_json + '\n' # to avoid diff "no newline" warning line
--- /dev/null
+"""This module contains single class, to store a sorted list."""
+# Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Eclipse Public License v1.0 which accompanies this distribution,
+# and is available at http://www.eclipse.org/legal/epl-v10.html
+
+__author__ = "Vratko Polak"
+__copyright__ = "Copyright(c) 2015, Cisco Systems, Inc."
+__license__ = "Eclipse Public License v1.0"
+__email__ = "vrpolak@cisco.com"
+
+
+class Hsfl(list):
+ """
+ Hashable sorted frozen list implementation stub.
+
+ Supports only __init__, __repr__ and __hash__ methods.
+ Other list methods are available, but they may break contract.
+ """
+
+ def __init__(self, *args, **kwargs):
+ """Contruct super, sort and compute repr and hash cache values."""
+ sup = super(Hsfl, self)
+ sup.__init__(*args, **kwargs)
+ sup.sort(key=repr)
+ self.__repr = repr(tuple(self))
+ self.__hash = hash(self.__repr)
+
+ def __repr__(self):
+ """Return cached repr string."""
+ return self.__repr
+
+ def __hash__(self):
+ """Return cached hash."""
+ return self.__hash
--- /dev/null
+"""This module contains single class, to store a sorted dict."""
+# Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Eclipse Public License v1.0 which accompanies this distribution,
+# and is available at http://www.eclipse.org/legal/epl-v10.html
+
+__author__ = "Vratko Polak"
+__copyright__ = "Copyright(c) 2015, Cisco Systems, Inc."
+__license__ = "Eclipse Public License v1.0"
+__email__ = "vrpolak@cisco.com"
+
+import collections as _collections
+
+
+class Hsfod(_collections.OrderedDict):
+ """
+ Hashable sorted (by key) frozen OrderedDict implementation stub.
+
+ Supports only __init__, __repr__ and __hash__ methods.
+ Other OrderedDict methods are available, but they may break contract.
+ """
+
+ def __init__(self, *args, **kwargs):
+ """Put arguments to OrderedDict, sort, pass to super, cache values."""
+ self_unsorted = _collections.OrderedDict(*args, **kwargs)
+ items_sorted = sorted(self_unsorted.items(), key=repr)
+ sup = super(Hsfod, self) # possibly something else than OrderedDict
+ sup.__init__(items_sorted)
+ # Repr string is used for sorting, keys are more important than values.
+ self.__repr = '{' + repr(self.keys()) + ':' + repr(self.values()) + '}'
+ self.__hash = hash(self.__repr)
+
+ def __repr__(self):
+ """Return cached repr string."""
+ return self.__repr
+
+ def __hash__(self):
+ """Return cached hash."""
+ return self.__hash
--- /dev/null
+*** Settings ***
+Documentation Basic tests for odl-bgpcep-pcep-all feature.
+...
+... Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+...
+... This program and the accompanying materials are made available under the
+... terms of the Eclipse Public License v1.0 which accompanies this distribution,
+... and is available at http://www.eclipse.org/legal/epl-v10.html
+Suite Setup Set_It_Up
+Suite Teardown Tear_It_Down
+Library OperatingSystem
+Library SSHLibrary prompt=]>
+Library ${CURDIR}/../../../libraries/RequestsLibrary.py
+Library ${CURDIR}/../../../libraries/HsfJson/hsf_json.py
+Variables ${CURDIR}/../../../variables/Variables.py
+Variables ${CURDIR}/../../../variables/basicpcep/variables.py ${MININET}
+
+*** Variables ***
+${ExpDir} ${CURDIR}/expected
+${ActDir} ${CURDIR}/actual
+
+*** Test Cases ***
+Topology_Precondition
+ [Documentation] Compare current pcep-topology to "offjson" variable.
+ ... Timeout is long enough to see that pcep is ready, with no PCC is connected.
+ [Tags] critical
+ Wait_Until_Keyword_Succeeds 900 1 Compare_Topology ${offjson} Pre
+
+Start_Pcc_Mock
+ [Documentation] Execute pcc-mock on Mininet, fail is Open is not sent, keep it running for next tests.
+ ${command}= Set_Variable java -jar ${filename} --local-address ${MININET} --remote-address ${CONTROLLER} 2>&1 | tee pccmock.log
+ Log ${command}
+ Write ${command}
+ Read_Until started, sent proposal Open
+
+Topology_Intercondition
+ [Documentation] Compare pcep-topology to "onjson", which includes a tunnel from pcc-mock.
+ [Tags] critical
+ Wait_Until_Keyword_succeeds 30 1 Compare_Topology ${onjson} Inter
+
+Stop_Pcc_Mock
+ [Documentation] Send ctrl+c to pcc-mock, fails if no prompt is seen
+ ... after 3 seconds (the default for SSHLibrary)
+ ${command}= Evaluate chr(int(3))
+ Log ${command}
+ Write ${command}
+ Read_Until_Prompt
+
+Topology_Postcondition
+ [Documentation] Compare curent pcep-topology to "offjson" again.
+ ... Timeout is lower than in Precondition,
+ ... but data from pcc-mock should be gone quickly.
+ [Tags] critical
+ Wait_Until_Keyword_Succeeds 30 1 Compare_Topology ${offjson} Post
+
+*** Keywords ***
+Set_It_Up
+ [Documentation] Create SSH session to Mininet machine, prepare HTTP client session to Controller.
+ ... Figure out latest pcc-mock version and download it from Nexus to Mininet.
+ ... Also, delete and create directories for json diff handling.
+ Open_Connection ${MININET}
+ Login_With_Public_Key ${MININET_USER} ${USER_HOME}/.ssh/id_rsa any
+ Create_Session ses http://${CONTROLLER}:8181/restconf/operational/network-topology:network-topology auth=${AUTH}
+ ${urlbase}= Set_Variable https://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/org/opendaylight/bgpcep/pcep-pcc-mock
+ ${version}= Execute_Command curl ${urlbase}/maven-metadata.xml | grep latest | cut -d '>' -f 2 | cut -d '<' -f 1
+ Log ${version}
+ ${namepart}= Execute_Command curl ${urlbase}/${version}/maven-metadata.xml | grep value | head -n 1 | cut -d '>' -f 2 | cut -d '<' -f 1
+ Log ${namepart}
+ Set_Suite_Variable ${filename} pcep-pcc-mock-${namepart}-executable.jar
+ Log ${filename}
+ ${response}= Execute_Command wget -q -N ${urlbase}/${version}/${filename} 2>&1
+ Log ${response}
+ Remove_Directory ${ExpDir}
+ Remove_Directory ${ActDir}
+ Create_Directory ${ExpDir}
+ Create_Directory ${ActDir}
+
+Compare_Topology
+ [Arguments] ${expected} ${name}
+ [Documentation] Get current pcep-topology as json, normalize both expected and actual json.
+ ... Save normalized jsons to files for later processing.
+ ... Error codes and normalized jsons should match exactly.
+ ${normexp}= Hsf_Json ${expected}
+ Log ${normexp}
+ Create_File ${ExpDir}${/}${name} ${normexp}
+ ${resp}= RequestsLibrary.Get ses topology/pcep-topology
+ Log ${resp}
+ Log ${resp.text}
+ ${normresp}= Hsf_Json ${resp.text}
+ Log ${normresp}
+ Create_File ${ActDir}${/}${name} ${normresp}
+ Should_Be_Equal_As_Strings ${resp.status_code} 200
+ Should_Be_Equal ${normresp} ${normexp}
+
+Tear_It_Down
+ [Documentation] Download pccmock.log and Log its contents.
+ ... Compute and Log the diff between expected and actual normalized responses.
+ ... Close both HTTP client session and SSH connection to Mininet.
+ SSHLibrary.Get_File pccmock.log
+ ${pccmocklog}= Run cat pccmock.log
+ Log ${pccmocklog}
+ ${diff}= Run diff -dur ${ExpDir} ${ActDir}
+ Log ${diff}
+ Delete_All_Sessions
+ Close_All_Connections
--- /dev/null
+# Place the suites in run order:
+integration/test/csit/suites/bgpcep/basicpcep
--- /dev/null
+"""Variables file for basicpcep suite.
+
+Expected JSON templates are fairly long,
+therefore there are moved out of testcase file.
+Also, it is needed to generate base64 encoded tunnel name
+from Mininet IP (which is not known beforehand),
+so it is easier to employ Python here,
+than do manipulation in Robot file."""
+# Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Eclipse Public License v1.0 which accompanies this distribution,
+# and is available at http://www.eclipse.org/legal/epl-v10.html
+
+__author__ = "Vratko Polak"
+__copyright__ = "Copyright(c) 2015, Cisco Systems, Inc."
+__license__ = "Eclipse Public License v1.0"
+__email__ = "vrpolak@cisco.com"
+
+import binascii
+from string import Template
+
+
+def get_variables(mininet_ip):
+ """Return dict of variables for the given IP addtess of Mininet VM."""
+ tunnelname = 'pcc_' + mininet_ip + '_tunnel_1'
+ pathcode = binascii.b2a_base64(tunnelname)[:-1] # remove endline
+ offjson = '''{
+ "topology": [
+ {
+ "topology-id": "pcep-topology",
+ "topology-types": {
+ "network-topology-pcep:topology-pcep": {}
+ }
+ }
+ ]
+}'''
+ onjsontempl = Template('''{
+ "topology": [
+ {
+ "node": [
+ {
+ "network-topology-pcep:path-computation-client": {
+ "ip-address": "$IP",
+ "reported-lsp": [
+ {
+ "name": "$NAME",
+ "path": [
+ {
+ "ero": {
+ "ignore": false,
+ "processing-rule": false,
+ "subobject": [
+ {
+ "ip-prefix": {
+ "ip-prefix": "1.1.1.1/32"
+ },
+ "loose": false
+ }
+ ]
+ },
+ "lsp-id": 1,
+ "odl-pcep-ietf-stateful07:lsp": {
+ "administrative": true,
+ "delegate": true,
+ "ignore": false,
+ "odl-pcep-ietf-initiated00:create": false,
+ "operational": "up",
+ "plsp-id": 1,
+ "processing-rule": false,
+ "remove": false,
+ "sync": true,
+ "tlvs": {
+ "lsp-identifiers": {
+ "ipv4": {
+ "ipv4-extended-tunnel-id": "$IP",
+ "ipv4-tunnel-endpoint-address": "1.1.1.1",
+ "ipv4-tunnel-sender-address": "$IP"
+ },
+ "lsp-id": 1,
+ "tunnel-id": 1
+ },
+ "symbolic-path-name": {
+ "path-name": "$CODE"
+ }
+ }
+ }
+ }
+ ]
+ }
+ ],
+ "state-sync": "synchronized",
+ "stateful-tlv": {
+ "odl-pcep-ietf-stateful07:stateful": {
+ "lsp-update-capability": true,
+ "odl-pcep-ietf-initiated00:initiation": true
+ }
+ }
+ },
+ "node-id": "pcc://$IP"
+ }
+ ],
+ "topology-id": "pcep-topology",
+ "topology-types": {
+ "network-topology-pcep:topology-pcep": {}
+ }
+ }
+ ]
+}''')
+ repl_dict = {'IP': mininet_ip, 'NAME': tunnelname, 'CODE': pathcode}
+ onjson = onjsontempl.substitute(repl_dict)
+ variables = {'offjson': offjson, 'onjson': onjson}
+ return variables