Add ODL tests from ODL integration suites 80/280/1
authorPeter Bandzi <pbandzi@cisco.com>
Thu, 9 Apr 2015 08:39:48 +0000 (10:39 +0200)
committerPeter Bandzi <pbandzi@cisco.com>
Thu, 9 Apr 2015 08:58:07 +0000 (10:58 +0200)
Tests are from https://github.com/opendaylight/integration
Most of test suites and libs are removed.
As they requires either additioanl features in ODL
or mininet environment atached to ODL.

For neutron test suite there are 3 tests added
which delete created networks, subnets, ports.

JIRA: FUNCTEST-5

Change-Id: I96b41b5df394795bf10aec2bbb0c5de0e63b950c
Signed-off-by: Peter Bandzi <pbandzi@cisco.com>
12 files changed:
testcases/Controllers/ODL/CI/libraries/Common.py [new file with mode: 0644]
testcases/Controllers/ODL/CI/libraries/RequestsLibrary.py [new file with mode: 0644]
testcases/Controllers/ODL/CI/libraries/Utils.txt [new file with mode: 0644]
testcases/Controllers/ODL/CI/suites/openstack/neutron/010__networks.txt [new file with mode: 0644]
testcases/Controllers/ODL/CI/suites/openstack/neutron/020__subnets.txt [new file with mode: 0644]
testcases/Controllers/ODL/CI/suites/openstack/neutron/030__ports.txt [new file with mode: 0644]
testcases/Controllers/ODL/CI/suites/openstack/neutron/040__delete_ports.txt [new file with mode: 0644]
testcases/Controllers/ODL/CI/suites/openstack/neutron/050__delete_subnets.txt [new file with mode: 0644]
testcases/Controllers/ODL/CI/suites/openstack/neutron/060__delete_networks.txt [new file with mode: 0644]
testcases/Controllers/ODL/CI/suites/openstack/neutron/__init__.txt [new file with mode: 0644]
testcases/Controllers/ODL/CI/variables/Variables.py [new file with mode: 0644]
testcases/Controllers/ODL/ODL.md [new file with mode: 0644]

diff --git a/testcases/Controllers/ODL/CI/libraries/Common.py b/testcases/Controllers/ODL/CI/libraries/Common.py
new file mode 100644 (file)
index 0000000..e748caa
--- /dev/null
@@ -0,0 +1,81 @@
+"""
+Library for the robot based system test tool of the OpenDaylight project.
+Authors: Baohua Yang@IBM, Denghui Huang@IBM
+Updated: 2013-11-14
+"""
+import collections
+import xml.etree.ElementTree as ET
+
+'''
+Common constants and functions for the robot framework.
+'''
+
+def collection_should_contain(collection, *members):
+    """
+    Fail if not every members is in the collection.
+    """
+    if not isinstance(collection, collections.Iterable):
+        return False
+    for m in members:
+        if m not in collection:
+            return False
+    else:
+        return True
+
+def combine_strings(*strings):
+    """
+    Combines the given `strings` together and returns the result.
+    The given strings are not altered by this keyword.
+    """
+    result = ''
+    for s in strings:
+        if isinstance(s,str) or isinstance(s,unicode):
+            result += s
+    if result == '':
+        return None
+    else:
+        return result
+
+        
+def compare_xml(xml1, xml2):
+    """
+    compare the two XML files to see if they contain the same data
+    but could be if different order.
+    It just split the xml in to lines and just check the line is in
+    the other file 
+    """
+    for line in xml1.rstrip().split('\n'):
+        if line not in xml2.rstrip().split('\n'):
+            return False
+
+    for line in xml2.rstrip().split('\n'):
+        if line not in xml1.rstrip().split('\n'):
+            return False
+
+    return True
+
+def num_of_nodes(depth, fanout):
+    '''returns num of switches of a mininet with tree topology 
+    with particular depth and fanout parameters
+    '''
+    result = 0
+    for i in xrange(depth):
+        result += fanout**i
+    return result    
+
+def num_of_links_for_node(nodeid, leaflist, fanout):
+    '''
+    If the given node is a leaf node, there will be an only one link for it
+    and nodeid will be represented 2 times in topology
+    If the given node is not a leaf node, then there will be fanout+1 links
+    for it and nodeid will be represented (fanout+1)*2 times in topology
+    
+    p.s. root node is excluded.
+    '''
+    if nodeid in leaflist:
+        return 1
+    return (fanout+1)
+
+if __name__ == '__main__':
+       print num_of_nodes(3,4)
+       pass
diff --git a/testcases/Controllers/ODL/CI/libraries/RequestsLibrary.py b/testcases/Controllers/ODL/CI/libraries/RequestsLibrary.py
new file mode 100644 (file)
index 0000000..3ef4375
--- /dev/null
@@ -0,0 +1,264 @@
+import requests
+import json
+
+from urllib import urlencode
+
+
+import robot
+
+from robot.libraries.BuiltIn import BuiltIn
+
+
+class RequestsLibrary(object):
+    ROBOT_LIBRARY_SCOPE = 'Global'
+
+    def __init__(self):
+        self._cache = robot.utils.ConnectionCache('No sessions created')
+        self.builtin = BuiltIn()
+
+    def _utf8_urlencode(self, data):
+        if not type(data) is dict:
+            return data
+
+        utf8_data = {}
+        for k,v in data.iteritems():
+            utf8_data[k] = unicode(v).encode('utf-8')
+        return urlencode(utf8_data)
+
+    def create_session(self, alias, url, headers={}, cookies=None,
+                       auth=None, timeout=None, proxies=None,
+                       verify=False):
+
+        """ Create Session: create a HTTP session to a server
+
+        `url` Base url of the server
+
+        `alias` Robot Framework alias to identify the session
+
+        `headers` Dictionary of default headers
+
+        `auth` Dictionary of username & password for HTTP Basic Auth
+
+        `timeout` connection timeout
+
+        `proxies` proxy server url
+
+        `verify` set to True if Requests should verify the certificate
+        """
+
+        self.builtin.log('Creating session: %s' % alias, 'DEBUG')
+        auth = requests.auth.HTTPBasicAuth(*auth) if auth else None
+        s = session = requests.Session()
+        s.headers.update(headers)
+        s.auth = auth if auth else s.auth
+        s.proxies = proxies if proxies else  s.proxies
+
+        s.verify = self.builtin.convert_to_boolean(verify)
+
+        # cant pass these into the Session anymore
+        self.timeout = timeout
+        self.cookies = cookies
+        self.verify = verify
+
+        # cant use hooks :(
+        s.url = url
+
+        self._cache.register(session, alias=alias)
+        return session
+
+    def delete_all_sessions(self):
+        """ Removes all the session objects """
+
+        self._cache.empty_cache()
+
+    def to_json(self, content):
+        """ Convert a string to a JSON object
+
+        `content` String content to convert into JSON
+        """
+        return json.loads(content)
+
+    
+    def _get_url(self, session, uri):
+        ''' Helpere method to get the full url
+        '''
+        url = session.url
+        if uri:
+            slash = '' if uri.startswith('/') else '/'
+            url = "%s%s%s" %(session.url, slash, uri)
+        return url
+
+    def get(self, alias, uri, headers=None):
+        """ Send a GET request on the session object found using the
+            given `alias`
+
+        `alias` that will be used to identify the Session object in the cache
+
+        `uri` to send the GET request to
+
+        `headers` a dictionary of headers to use with the request
+        """
+
+        session = self._cache.switch(alias)
+        resp = session.get(self._get_url(session, uri),
+                           headers=headers,
+                           cookies=self.cookies, timeout=self.timeout)
+
+        # store the last response object
+        session.last_resp = resp
+        return resp
+
+    def post(self, alias, uri, data={}, headers=None, files={}):
+        """ Send a POST request on the session object found using the
+        given `alias`
+
+        `alias` that will be used to identify the Session object in the cache
+
+        `uri` to send the GET request to
+
+        `data` a dictionary of key-value pairs that will be urlencoded
+               and sent as POST data
+               or binary data that is sent as the raw body content
+
+        `headers` a dictionary of headers to use with the request
+
+        `files` a dictionary of file names containing file data to POST to the server
+        """
+
+        session = self._cache.switch(alias)
+        data = self._utf8_urlencode(data)
+
+        resp = session.post(self._get_url(session, uri),
+                       data=data, headers=headers,
+                       files=files,
+                       cookies=self.cookies, timeout=self.timeout)
+
+        # store the last response object
+        session.last_resp = resp
+        self.builtin.log("Post response: " + resp.content, 'DEBUG')
+        return resp
+
+    def postjson(self, alias, uri, data={}, headers=None, files={}):
+        """ Send a POST request on the session object found using the
+        given `alias`
+
+        `alias` that will be used to identify the Session object in the cache
+
+        `uri` to send the GET request to
+
+        `data` a dictionary of key-value pairs that will be urlencoded
+               and sent as POST data
+               or binary data that is sent as the raw body content
+
+        `headers` a dictionary of headers to use with the request
+
+        `files` a dictionary of file names containing file data to POST to the server
+        """
+
+        session = self._cache.switch(alias)
+        data = json.dumps(data)
+
+        resp = session.post(self._get_url(session, uri),
+                       data=data, headers=headers,
+                       files=files,
+                       cookies=self.cookies, timeout=self.timeout)
+
+        # store the last response object
+        session.last_resp = resp
+        self.builtin.log("Post response: " + resp.content, 'DEBUG')
+        return resp
+
+    def put(self, alias, uri, data=None, headers=None):
+        """ Send a PUT request on the session object found using the
+        given `alias`
+
+        `alias` that will be used to identify the Session object in the cache
+
+        `uri` to send the PUT request to
+
+        `headers` a dictionary of headers to use with the request
+
+        """
+
+        session = self._cache.switch(alias)
+       #data = self._utf8_urlencode(data)
+        data = json.dumps(data)
+
+        resp = session.put(self._get_url(session, uri),
+                    data=data, headers=headers,
+                    cookies=self.cookies, timeout=self.timeout)
+
+        self.builtin.log("PUT response: %s DEBUG" % resp.content)
+
+        # store the last response object
+        session.last_resp = resp
+        return resp
+
+    def put_xml(self, alias, uri, data=None, headers=None):
+        """ Send a PUT_xml request on the session object found using the
+        given `alias`
+
+        `alias` that will be used to identify the Session object in the cache
+
+        `uri` to send the PUT_xml request to
+
+        `headers` a dictionary of headers to use with the request
+
+        """
+
+        session = self._cache.switch(alias)
+       data = self._utf8_urlencode(data)
+        #data = json.dumps(data)
+
+        resp = session.put(self._get_url(session, uri),
+                    data=data, headers=headers,
+                    cookies=self.cookies, timeout=self.timeout)
+
+        self.builtin.log("PUT response: %s DEBUG" % resp.content)
+
+        # store the last response object
+        session.last_resp = resp
+        return resp
+
+    def delete(self, alias, uri, data=(), headers=None):
+        """ Send a DELETE request on the session object found using the
+        given `alias`
+
+        `alias` that will be used to identify the Session object in the cache
+
+        `uri` to send the DELETE request to
+
+        `headers` a dictionary of headers to use with the request
+
+        """
+
+        session = self._cache.switch(alias)
+        args = "?%s" % urlencode(data) if data else ''
+        resp = session.delete("%s%s" % (self._get_url(session, uri), args),
+                            headers=headers, cookies=self.cookies,
+                            timeout=self.timeout)
+
+        # store the last response object
+        session.last_resp = resp
+        return resp
+
+       
+    def head(self, alias, uri, headers=None):
+        """ Send a HEAD request on the session object found using the
+        given `alias`
+
+        `alias` that will be used to identify the Session object in the cache
+
+        `uri` to send the HEAD request to
+
+        `headers` a dictionary of headers to use with the request
+
+        """
+
+        session = self._cache.switch(alias)
+        resp = session.head(self._get_url(session, uri), headers=headers,
+                           cookies=self.cookies, timeout=self.timeout)
+
+        # store the last response object
+        session.last_resp = resp
+        return resp
diff --git a/testcases/Controllers/ODL/CI/libraries/Utils.txt b/testcases/Controllers/ODL/CI/libraries/Utils.txt
new file mode 100644 (file)
index 0000000..913ba22
--- /dev/null
@@ -0,0 +1,106 @@
+*** Settings ***
+Library           SSHLibrary
+Library           ./UtilLibrary.py
+
+*** Variables ***
+${start}          sudo mn --controller=remote,ip=${CONTROLLER} --topo tree,1 --switch ovsk,protocols=OpenFlow13
+${linux_prompt}   >
+
+*** Keywords ***
+Start Suite
+    [Documentation]    Basic setup/cleanup work that can be done safely before any system
+    ...    is run.
+    Log    Start the test on the base edition
+    ${mininet_conn_id}=     Open Connection    ${MININET}    prompt=${linux_prompt}    timeout=30s
+    Set Suite Variable  ${mininet_conn_id}
+    Login With Public Key    ${MININET_USER}    ${USER_HOME}/.ssh/id_rsa    any
+    Write    sudo ovs-vsctl set-manager ptcp:6644
+    Read Until    ${linux_prompt}
+    Write    sudo mn -c
+    Read Until    ${linux_prompt}
+    Write    ${start}
+    Read Until    mininet>
+    Sleep    6
+
+Stop Suite
+    [Documentation]    Cleanup/Shutdown work that should be done at the completion of all
+    ...    tests
+    Log    Stop the test on the base edition
+    Switch Connection   ${mininet_conn_id}
+    Read
+    Write    exit
+    Read Until    ${linux_prompt}
+    Close Connection
+
+Ensure All Nodes Are In Response
+    [Arguments]    ${URI}    ${node_list}
+    [Documentation]    A GET is made to the supplied ${URI} and every item in the ${node_list}
+    ...    is verified to exist in the repsonse. This keyword currently implies that it's node
+    ...    specific but any list of strings can be given in ${node_list}. Refactoring of this
+    ...    to make it more generic should be done. (see keyword "Check For Elements At URI")
+    : FOR    ${node}    IN    @{node_list}
+    \    ${resp}    RequestsLibrary.Get    session    ${URI}
+    \    Should Be Equal As Strings    ${resp.status_code}    200
+    \    Should Contain    ${resp.content}    ${node}
+
+Check Nodes Stats
+    [Arguments]    ${node}
+    [Documentation]    A GET on the /node/${node} API is made and specific flow stat
+    ...    strings are checked for existence.
+    ${resp}    RequestsLibrary.Get    session    ${REST_CONTEXT}/node/${node}
+    Should Be Equal As Strings    ${resp.status_code}    200
+    Should Contain    ${resp.content}    flow-capable-node-connector-statistics
+    Should Contain    ${resp.content}    flow-table-statistics
+
+Check That Port Count Is Ok
+    [Arguments]    ${node}    ${count}
+    [Documentation]    A GET on the /port API is made and the specified port ${count} is
+    ...    verified. A more generic Keyword "Check For Specific Number Of Elements At URI"
+    ...    also does this work and further consolidation should be done.
+    ${resp}    RequestsLibrary.Get    session    ${REST_CONTEXT}/${CONTAINER}/port
+    Log    ${resp.content}
+    Should Be Equal As Strings    ${resp.status_code}    200
+    Should Contain X Times    ${resp.content}    ${node}    ${count}
+
+Check For Specific Number Of Elements At URI
+    [Arguments]    ${uri}    ${element}    ${expected_count}
+    [Documentation]    A GET is made to the specified ${URI} and the specific count of a
+    ...    given element is done (as supplied by ${element} and ${expected_count})
+    ${resp}    RequestsLibrary.Get    session    ${uri}
+    Log    ${resp.content}
+    Should Be Equal As Strings    ${resp.status_code}    200
+    Should Contain X Times    ${resp.content}    ${element}    ${expected_count}
+
+Check For Elements At URI
+    [Arguments]    ${uri}    ${elements}
+    [Documentation]    A GET is made at the supplied ${URI} and every item in the list of
+    ...    ${elements} is verified to exist in the response
+    ${resp}    RequestsLibrary.Get    session    ${uri}
+    Log    ${resp.content}
+    Should Be Equal As Strings    ${resp.status_code}    200
+    : FOR    ${i}    IN    @{elements}
+    \    Should Contain    ${resp.content}    ${i}
+
+Check For Elements Not At URI
+    [Arguments]    ${uri}    ${elements}
+    [Documentation]    A GET is made at the supplied ${URI} and every item in the list of
+    ...    ${elements} is verified to NOT exist in the response
+    ${resp}    RequestsLibrary.Get    session    ${uri}
+    Log    ${resp.content}
+    Should Be Equal As Strings    ${resp.status_code}    200
+    : FOR    ${i}    IN    @{elements}
+    \    Should Not Contain    ${resp.content}    ${i}
+
+Extract Value From Content
+    [Arguments]    ${content}    ${index}    ${strip}=nostrip
+    [Documentation]    Will take the given response content and return the value at the given index as a string
+    ${value}=    Get Json Value    ${content}    ${index}
+    ${value}=    Convert To String    ${value}
+    ${value}=    Run Keyword If    '${strip}' == 'strip'    Strip Quotes    ${value}
+    [Return]    ${value}
+
+Strip Quotes
+    [Arguments]    ${string_to_strip}
+    [Documentation]    Will strip ALL quotes from given string and return the new string
+    ${string_to_return}=    Replace String    ${string_to_strip}    "    \    count=-1
+    [Return]    ${string_to_return}
diff --git a/testcases/Controllers/ODL/CI/suites/openstack/neutron/010__networks.txt b/testcases/Controllers/ODL/CI/suites/openstack/neutron/010__networks.txt
new file mode 100644 (file)
index 0000000..ac5080a
--- /dev/null
@@ -0,0 +1,58 @@
+*** Settings ***
+Documentation     Checking Network created in OpenStack are pushed to OpenDaylight
+Suite Setup      Create Session    OSSession     http://${OPENSTACK}:9696    headers=${X-AUTH}    
+Suite Teardown    Delete All Sessions
+Library           SSHLibrary
+Library           Collections
+Library           OperatingSystem
+Library           ../../../libraries/RequestsLibrary.py
+Library           ../../../libraries/Common.py
+Variables         ../../../variables/Variables.py
+*** Variables ***
+${ODLREST}       /controller/nb/v2/neutron/networks
+${OSREST}        /v2.0/networks
+${postNet}     {"network":{"name":"odl_network","admin_state_up":true}}
+*** Test Cases ***
+Check OpenStack Networks
+       [Documentation]     Checking OpenStack Neutron for known networks
+       [Tags]              Network Neutron OpenStack
+        Log    ${X-AUTH}
+        ${resp}                get     OSSession       ${OSREST}   
+       Should be Equal As Strings      ${resp.status_code}     200
+        ${OSResult}    To Json         ${resp.content}
+        Set Suite Variable     ${OSResult}
+        Log    ${OSResult}
+
+Check OpenDaylight Networks
+       [Documentation]    Checking OpenDaylight Neutron API for Known Networks
+        [Tags]                    Network Neutron OpenDaylight
+        Create Session ODLSession      http://${CONTROLLER}:${PORT}     headers=${HEADERS}  auth=${AUTH}
+        ${resp}        get     ODLSession      ${ODLREST}    
+       Should be Equal As Strings      ${resp.status_code}     200
+        ${ODLResult}   To Json         ${resp.content}
+        Set Suite Variable     ${ODLResult}
+        Log    ${ODLResult}
+
+Create Network 
+       [Documentation]    Create new network in OpenStack
+       [Tags]             Create Network OpenStack Neutron
+        Log    ${postNet}
+        ${resp}                post    OSSession       ${OSREST}  data=${postNet}  
+        Should be Equal As Strings     ${resp.status_code}     201
+       ${result}       To JSON         ${resp.content}
+       ${result}       Get From Dictionary     ${result}       network 
+        ${NETID}       Get From Dictionary     ${result}       id
+        Log    ${result}
+       Log     ${NETID}
+        Set Global Variable    ${NETID}
+        sleep    2
+
+Check Network
+       [Documentation]   Check Network created in OpenDaylight
+       [Tags]          Check  Network OpenDaylight
+       ${resp}         get     ODLSession      ${ODLREST}/${NetID}
+        Should be Equal As Strings     ${resp.status_code}     200
+
+
diff --git a/testcases/Controllers/ODL/CI/suites/openstack/neutron/020__subnets.txt b/testcases/Controllers/ODL/CI/suites/openstack/neutron/020__subnets.txt
new file mode 100644 (file)
index 0000000..5e0c417
--- /dev/null
@@ -0,0 +1,58 @@
+*** Settings ***
+Documentation     Checking Subnets  created in OpenStack are pushed to OpenDaylight
+Suite Setup      Create Session    OSSession     http://${OPENSTACK}:9696    headers=${X-AUTH}    
+Suite Teardown    Delete All Sessions
+Library           SSHLibrary
+Library           Collections
+Library           OperatingSystem
+Library           ../../../libraries/RequestsLibrary.py
+Library           ../../../libraries/Common.py
+Variables         ../../../variables/Variables.py
+*** Variables ***
+${ODLREST}       /controller/nb/v2/neutron/subnets
+${OSREST}        /v2.0/subnets
+${data}       {"subnet":{"name":"odl_subnet","network_id":"${NETID}","ip_version":4,"cidr":"172.16.64.0/24","allocation_pools":[{"start":"172.16.64.20","end":"172.16.64.120"}]}}
+*** Test Cases ***
+Check OpenStack Subnets
+       [Documentation]     Checking OpenStack Neutron for known Subnets
+       [Tags]              Subnets Neutron OpenStack
+        Log    ${X-AUTH}
+        ${resp}                get     OSSession       ${OSREST}    
+       Should be Equal As Strings      ${resp.status_code}     200
+        ${OSResult}    To Json         ${resp.content}
+        Set Suite Variable     ${OSResult}
+        Log    ${OSResult}
+
+Check OpenDaylight subnets
+       [Documentation]    Checking OpenDaylight Neutron API for Known Subnets
+        [Tags]                    Subnets Neutron OpenDaylight
+        Create Session ODLSession      http://${CONTROLLER}:${PORT}     headers=${HEADERS}  auth=${AUTH}
+        ${resp}        get     ODLSession      ${ODLREST}    
+       Should be Equal As Strings      ${resp.status_code}     200
+        ${ODLResult}   To Json         ${resp.content}
+        Set Suite Variable     ${ODLResult}
+        Log    ${ODLResult}
+
+Create New subnet
+       [Documentation]    Create new subnet in OpenStack
+       [Tags]             Create Subnet OpenStack Neutron
+        Log    ${data}
+        ${resp}                post    OSSession       ${OSREST}       data=${data}  
+        Should be Equal As Strings     ${resp.status_code}     201
+       ${result}       To JSON         ${resp.content}
+       ${result}       Get From Dictionary     ${result}       subnet  
+        ${SUBNETID}    Get From Dictionary     ${result}       id
+        Log    ${result}
+       Log     ${SUBNETID}
+        Set Global Variable    ${SUBNETID}
+        sleep    2
+
+Check New subnet
+       [Documentation]   Check new subnet created in OpenDaylight
+       [Tags]          Check  subnet OpenDaylight
+       ${resp}         get     ODLSession      ${ODLREST}/${SUBNETID}
+        Should be Equal As Strings     ${resp.status_code}     200
+
+
diff --git a/testcases/Controllers/ODL/CI/suites/openstack/neutron/030__ports.txt b/testcases/Controllers/ODL/CI/suites/openstack/neutron/030__ports.txt
new file mode 100644 (file)
index 0000000..5aafd51
--- /dev/null
@@ -0,0 +1,58 @@
+*** Settings ***
+Documentation     Checking Port  created in OpenStack are pushed to OpenDaylight
+Suite Setup      Create Session    OSSession     http://${OPENSTACK}:9696    headers=${X-AUTH}    
+Suite Teardown    Delete All Sessions
+Library           SSHLibrary
+Library           Collections
+Library           OperatingSystem
+Library           ../../../libraries/RequestsLibrary.py
+Library           ../../../libraries/Common.py
+Variables         ../../../variables/Variables.py
+*** Variables ***
+${ODLREST}       /controller/nb/v2/neutron/ports
+${OSREST}        /v2.0/ports
+${data}       {"port":{"name":"odl_port","network_id":"${NETID}","admin_state_up": true}}
+*** Test Cases ***
+Check OpenStack ports
+       [Documentation]     Checking OpenStack Neutron for known ports
+       [Tags]              Ports Neutron OpenStack
+        Log    ${X-AUTH}
+        ${resp}                get     OSSession       ${OSREST}    
+       Should be Equal As Strings      ${resp.status_code}     200
+        ${OSResult}    To Json         ${resp.content}
+        Set Suite Variable     ${OSResult}
+        Log    ${OSResult}
+
+Check OpenDaylight ports
+       [Documentation]    Checking OpenDaylight Neutron API for Known Ports
+        [Tags]                    Ports Neutron OpenDaylight
+        Create Session ODLSession      http://${CONTROLLER}:${PORT}     headers=${HEADERS}  auth=${AUTH}
+        ${resp}        get     ODLSession      ${ODLREST}    
+       Should be Equal As Strings      ${resp.status_code}     200
+        ${ODLResult}   To Json         ${resp.content}
+        Set Suite Variable     ${ODLResult}
+        Log    ${ODLResult}
+
+Create New Port
+       [Documentation]    Create new port in OpenStack
+       [Tags]             Create port OpenStack Neutron
+        Log    ${data}
+        ${resp}                post    OSSession       ${OSREST}       data=${data}  
+        Should be Equal As Strings     ${resp.status_code}     201
+       ${result}       To JSON         ${resp.content}
+       ${result}       Get From Dictionary     ${result}       port    
+        ${PORTID}      Get From Dictionary     ${result}       id
+        Log    ${result}
+       Log     ${PORTID}
+        Set Global Variable    ${PORTID}
+        sleep    2
+
+Check New Port
+       [Documentation]   Check new port created in OpenDaylight
+       [Tags]          Check  subnet OpenDaylight
+       ${resp}         get     ODLSession      ${ODLREST}/${PORTID}
+        Should be Equal As Strings     ${resp.status_code}     200
+
+
diff --git a/testcases/Controllers/ODL/CI/suites/openstack/neutron/040__delete_ports.txt b/testcases/Controllers/ODL/CI/suites/openstack/neutron/040__delete_ports.txt
new file mode 100644 (file)
index 0000000..5aca2c8
--- /dev/null
@@ -0,0 +1,37 @@
+*** Settings ***
+Documentation     Checking Port deleted in OpenStack are deleted also in OpenDaylight
+Suite Setup      Create Session    OSSession     http://${OPENSTACK}:9696    headers=${X-AUTH}    
+Suite Teardown    Delete All Sessions
+Library           SSHLibrary
+Library           Collections
+Library           OperatingSystem
+Library           ../../../libraries/RequestsLibrary.py
+Library           ../../../libraries/Common.py
+Variables         ../../../variables/Variables.py
+*** Variables ***
+${ODLREST}       /controller/nb/v2/neutron/ports
+${OSREST}        /v2.0/ports/${PORTID}
+${data}       {"port":{"network_id":"${NETID}","admin_state_up": true}}
+*** Test Cases ***
+Delete New Port
+       [Documentation]    Delete previously created port in OpenStack
+       [Tags]             Delete port OpenStack Neutron
+        Log    ${data}
+        ${resp}                delete  OSSession       ${OSREST}
+        Should be Equal As Strings     ${resp.status_code}     204
+        Log    ${resp.content}
+        sleep    2
+
+Check Port Deleted
+       [Documentation]   Check port deleted in OpenDaylight
+       [Tags]          Check port deleted OpenDaylight
+        Create Session ODLSession      http://${CONTROLLER}:${PORT}     headers=${HEADERS}  auth=${AUTH}
+        ${resp}        get     ODLSession      ${ODLREST}    
+       Should be Equal As Strings      ${resp.status_code}     200
+        ${ODLResult}   To Json         ${resp.content}
+        Set Suite Variable     ${ODLResult}
+        Log    ${ODLResult}
+       ${resp}         get     ODLSession      ${ODLREST}/${PORTID}
+        Should be Equal As Strings     ${resp.status_code}     404
diff --git a/testcases/Controllers/ODL/CI/suites/openstack/neutron/050__delete_subnets.txt b/testcases/Controllers/ODL/CI/suites/openstack/neutron/050__delete_subnets.txt
new file mode 100644 (file)
index 0000000..04c73cc
--- /dev/null
@@ -0,0 +1,37 @@
+*** Settings ***
+Documentation     Checking Subnets deleted in OpenStack are deleted also in OpenDaylight
+Suite Setup      Create Session    OSSession     http://${OPENSTACK}:9696    headers=${X-AUTH}    
+Suite Teardown    Delete All Sessions
+Library           SSHLibrary
+Library           Collections
+Library           OperatingSystem
+Library           ../../../libraries/RequestsLibrary.py
+Library           ../../../libraries/Common.py
+Variables         ../../../variables/Variables.py
+*** Variables ***
+${ODLREST}       /controller/nb/v2/neutron/subnets
+${OSREST}        /v2.0/subnets/${SUBNETID}
+${data}       {"subnet":{"network_id":"${NETID}","ip_version":4,"cidr":"172.16.64.0/24","allocation_pools":[{"start":"172.16.64.20","end":"172.16.64.120"}]}}
+*** Test Cases ***
+Delete New subnet
+       [Documentation]    Delete previously created subnet in OpenStack
+       [Tags]             Delete Subnet OpenStack Neutron
+        Log    ${data}
+        ${resp}                delete  OSSession       ${OSREST}       
+        Should be Equal As Strings     ${resp.status_code}     204
+        Log    ${resp.content}
+        sleep    2
+
+Check New subnet deleted
+       [Documentation]   Check subnet deleted in OpenDaylight
+       [Tags]          Check subnet deleted OpenDaylight
+        Create Session ODLSession      http://${CONTROLLER}:${PORT}     headers=${HEADERS}  auth=${AUTH}
+        ${resp}        get     ODLSession      ${ODLREST}    
+       Should be Equal As Strings      ${resp.status_code}     200
+        ${ODLResult}   To Json         ${resp.content}
+        Set Suite Variable     ${ODLResult}
+        Log    ${ODLResult}
+       ${resp}         get     ODLSession      ${ODLREST}/${SUBNETID}
+        Should be Equal As Strings     ${resp.status_code}     404
diff --git a/testcases/Controllers/ODL/CI/suites/openstack/neutron/060__delete_networks.txt b/testcases/Controllers/ODL/CI/suites/openstack/neutron/060__delete_networks.txt
new file mode 100644 (file)
index 0000000..31963ec
--- /dev/null
@@ -0,0 +1,37 @@
+*** Settings ***
+Documentation     Checking Network deleted in OpenStack are deleted also in OpenDaylight
+Suite Setup      Create Session    OSSession     http://${OPENSTACK}:9696    headers=${X-AUTH}    
+Suite Teardown    Delete All Sessions
+Library           SSHLibrary
+Library           Collections
+Library           OperatingSystem
+Library           ../../../libraries/RequestsLibrary.py
+Library           ../../../libraries/Common.py
+Variables         ../../../variables/Variables.py
+*** Variables ***
+${ODLREST}       /controller/nb/v2/neutron/networks
+${OSREST}        /v2.0/networks/${NETID}
+${postNet}     {"network":{"name":"odl_network","admin_state_up":true}}
+*** Test Cases ***
+Delete Network 
+       [Documentation]    Delete network in OpenStack
+       [Tags]             Delete Network OpenStack Neutron
+        Log    ${postNet}
+        ${resp}                delete  OSSession       ${OSREST}  
+        Should be Equal As Strings     ${resp.status_code}     204
+        Log    ${resp.content}
+        sleep    2
+
+Check Network deleted
+       [Documentation]   Check Network deleted in OpenDaylight
+       [Tags]          Check  Network OpenDaylight
+        Create Session ODLSession      http://${CONTROLLER}:${PORT}     headers=${HEADERS}  auth=${AUTH}
+        ${resp}        get     ODLSession      ${ODLREST}    
+       Should be Equal As Strings      ${resp.status_code}     200
+        ${ODLResult}   To Json         ${resp.content}
+        Set Suite Variable     ${ODLResult}
+        Log    ${ODLResult}
+       ${resp}         get     ODLSession      ${ODLREST}/${NetID}
+        Should be Equal As Strings     ${resp.status_code}     404
diff --git a/testcases/Controllers/ODL/CI/suites/openstack/neutron/__init__.txt b/testcases/Controllers/ODL/CI/suites/openstack/neutron/__init__.txt
new file mode 100644 (file)
index 0000000..4112b32
--- /dev/null
@@ -0,0 +1,27 @@
+*** Settings ***
+Documentation     Test suite for Neutron Plugin
+Suite Setup       Start Suite
+Suite Teardown    Stop Suite
+Library     SSHLibrary
+Library     Collections
+Library     ../../../libraries/RequestsLibrary.py
+Library     ../../../libraries/Common.py
+Variables   ../../../variables/Variables.py
+
+*** Variables ***
+${UserInfo}=  {"auth": {"tenantName": "admin", "passwordCredentials": {"username": "admin", "password": "octopus"}}}
+
+** Keywords ***
+Start Suite
+    Create Session  KeyStoneSession    http://${OPENSTACK}:5000      headers=${HEADERS}
+    ${resp}      post    KeyStoneSession     /v2.0/tokens    ${UserInfo}
+    Should Be Equal As Strings    ${resp.status_code}     200
+    ${result}  To JSON   ${resp.content}
+    ${result}   Get From Dictionary   ${result}  access
+    ${result}   Get From Dictionary   ${result}  token
+    ${TOKEN}   Get From Dictionary   ${result}  id
+    ${X-AUTH}  Create Dictionary     X-Auth-Token      ${TOKEN}    Content-Type     application/json      
+    Set Global Variable   ${X-AUTH}
+Stop Suite
+    Delete All Sessions
+
diff --git a/testcases/Controllers/ODL/CI/variables/Variables.py b/testcases/Controllers/ODL/CI/variables/Variables.py
new file mode 100644 (file)
index 0000000..f406eec
--- /dev/null
@@ -0,0 +1,20 @@
+"""
+Library for the robot based system test tool of the OpenDaylight project.
+"""
+import collections
+
+# Global variables
+CONTROLLER = '10.2.91.18'
+PORT = '8081'
+PREFIX = 'http://' + CONTROLLER + ':' + PORT
+USER = 'admin'
+PWD = 'admin'
+AUTH = [u'admin',u'admin']
+HEADERS={'Content-Type': 'application/json'}
+HEADERS_XML={'Content-Type': 'application/xml'}
+ACCEPT_XML={'Accept': 'application/xml'}
+
+#TOKEN
+AUTH_TOKEN_API='/oauth2/token'
+REVOKE_TOKEN_API='/oauth2/revoke'
+
diff --git a/testcases/Controllers/ODL/ODL.md b/testcases/Controllers/ODL/ODL.md
new file mode 100644 (file)
index 0000000..ceb0419
--- /dev/null
@@ -0,0 +1,33 @@
+# Robotframework test for ODL
+
+Original ODL testsuites can be found here: https://github.com/opendaylight/integration
+
+## Environment for running tests
+
+Create python virtual environment and install following packages into it:
+
+BeautifulSoup==3.2.1
+PyYAML==3.11
+contextdecorator==0.10.0
+ecdsa==0.11
+ipaddr==2.1.11
+paramiko==1.14.0
+pycrypto==2.6.1
+pystache==0.5.4
+requests==2.3.0
+robotframework==2.8.5
+robotframework-requests==0.3.7
+robotframework-sshlibrary==2.0.2
+six==1.7.3
+vcrpy==1.0.2
+wsgiref==0.1.2
+
+## Running tests
+
+Parameters are specified in:
+
+ODL/variables/Variables.py
+
+but can be also overidden in command line e.g.:
+
+pybot -v OPENSTACK:10.2.91.18 -v PORT:8081 -v CONTROLLER 10.2.91.18 .