--- /dev/null
+"""
+Library for ALTO project robot system test framework.
+Author: linxiao9292@outlook.com
+"""
+
+import json
+import re
+
+content_key_set = {"meta", "resources"}
+resource_key_set = {"uri", "media-type", "accepts", "capabilities", "uses"}
+cost_type_key_set = {"cost-mode", "cost-metric", "description"}
+media_type_set = {"application/alto-directory+json",
+ "application/alto-networkmap+json",
+ "application/alto-networkmapfilter+json",
+ "application/alto-costmap+json",
+ "application/alto-costmapfilter+json",
+ "application/alto-endpointprop+json",
+ "application/alto-endpointpropparams+json",
+ "application/alto-endpointcost+json",
+ "application/alto-endpointcostparams+json",
+ "application/alto-error+json"
+ }
+
+
+def get_basic_info(response):
+ """Get basic information of the simple IRD.
+
+ Args:
+ :param response: response from restconf/operational/alto-simple-ird:information
+ contains context-id and base-url for alto-simple-ird.
+ Returns:
+ :returns tuple: context-id - Identifier of different implementations of one service.
+ The formation of it is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
+ For example, we have three implementations of IRD service, and we could use
+ different context-id to identify them.
+
+ base-url - ALTO northbound URL of simple IRD.
+ """
+ resp = json.loads(response)
+ return resp["information"]["context-id"], resp["information"]["base-url"]
+
+
+def check_ird_configuration_entry(response, ird_resource_id, context_id, resource_id):
+ """Check whether resources we added are in the resource pool.
+
+ Args:
+ :param response: response from restconf/operational/alto-resourcepool:context/context-id
+ context-id is from get_basic_info(response).
+
+ :param ird_resource_id: ID of the IRD.
+
+ :param context_id: See above.
+
+ :param resource_id: ID of the resource.
+ context-id and resource-id together could determine one implementation of one service.
+ Returns:
+ :return bool: False if we do not get the resource we added before
+ """
+ resp = json.loads(response)
+ resources = resp["context"][0]["resource"]
+ for resource in resources:
+ if resource["resource-id"] == ird_resource_id:
+ context_tags = resource["context-tag"]
+ for tag in context_tags:
+ if "dependency" in tag:
+ for one_dependency in tag["dependency"]:
+ _context_id = re.findall("\d{8}-\d{4}-\d{4}-\d{4}-\d{12}", one_dependency)[0]
+ if _context_id == context_id:
+ long_resource_id = re.findall("resource-id='[a-zA-Z\-]*'", one_dependency)[0]
+ short_resource_id = re.findall("'.*'", long_resource_id)[0]
+ _resource_id = short_resource_id.replace("'", "")
+ if _resource_id == resource_id:
+ return True
+ return False
+
+
+def verify_ird(response):
+ """Semantic check of IRD response, more information in RFC 7285 9.2.
+
+ Args:
+ :param response: response from ALTO northbound URL of IRD.
+ Returns:
+ :return: bool: False if there are some semantic errors.
+ One semantic error is that we only define routing-cost in cost-type, but we find that one capability of a
+ resource is bandwidth.
+ """
+ if response.headers["content-type"] != "application/alto-directory+json":
+ return False
+ try:
+ resp = json.loads(response.content)
+ except ValueError:
+ return False
+ if "meta" not in resp:
+ return False
+ meta = resp["meta"]
+ if "cost-types" in meta:
+ cost_types = meta["cost-types"]
+ for cost_type in cost_types:
+ if set(cost_type).issubset(cost_type_key_set):
+ if "cost-mode" in cost_type and "cost-metric" in cost_type:
+ continue
+ else:
+ return False
+ else:
+ return False
+
+ resources = resp["resources"]
+ for resource in resources.keys():
+ if set(resources[resource].keys()).issubset(resource_key_set):
+ if "uri" not in resources[resource] or "media-type" not in resources[resource]:
+ return False
+ else:
+ _resource = resources[resource]
+ media_type = _resource["media-type"]
+ if media_type not in media_type_set:
+ return False
+ if "capabilities" in _resource:
+ capabilities = _resource["capabilities"]
+ if "cost-type-names" in capabilities:
+ cost_type_names = capabilities["cost-type-names"]
+ for cost_type_name in cost_type_names:
+ if cost_type_name not in cost_types:
+ return False
+ else:
+ return False
+ return True
--- /dev/null
+*** Settings ***
+Documentation Test suite for ALTO simple IRD (Information Resource Dictionary)
+Suite Setup Create Session session http://${CONTROLLER}:${RESTCONFPORT} auth=${AUTH} headers=${HEADERS}
+Suite Teardown Delete All Sessions
+Library RequestsLibrary
+Library ../../../libraries/ALTO/AltoParser.py
+Variables ../../../variables/Variables.py
+Variables ../../../variables/alto/Variables.py
+
+*** Variables ***
+${THE_FIRST_IRD_RESOURCE_ID} hello
+${THE_SECOND_IRD_RESOURCE_ID} world
+${RESOURCE_IN_FIRST_IRD} test-model-networkmap
+${RESOURCE_IN_SECOND_IRD} test-model-filtered-costmap
+${BASE_URL}
+${RANDOM_CONTEXT_ID}
+
+*** Test Cases ***
+Check the simple IRD information
+ [Documentation] Get the default IRD information
+ Wait Until Keyword Succeeds 5s 1s Check GET Response Code Equals 200 /${ALTO_SIMPLE_IRD_INFO}
+ ${resp} RequestsLibrary.Get Request session /${ALTO_SIMPLE_IRD_INFO}
+ ${context_id} ${BASE_URL} Get Basic Info ${resp.content}
+ Set Suite Variable ${BASE_URL}
+ Set Suite Variable ${RANDOM_CONTEXT_ID} ${context_id}
+ Wait Until Keyword Succeeds 5s 1s Check GET Response Code Equals 200 /${RESOURCE_POOL_BASE}/${context_id}
+
+Create two IRDs
+ [Documentation] Create two IRDs and verify their existence
+ Create An IRD ${DEFAULT_CONTEXT_ID} ${THE_FIRST_IRD_RESOURCE_ID}
+ Wait Until Keyword Succeeds 5s 1s Check GET Response Code Equals 200 /${ALTO_OPERATIONAL_IRD_INSTANCE}/${THE_FIRST_IRD_RESOURCE_ID}
+ Create An IRD ${DEFAULT_CONTEXT_ID} ${THE_SECOND_IRD_RESOURCE_ID}
+ Wait Until Keyword Succeeds 5s 1s Check GET Response Code Equals 200 /${ALTO_OPERATIONAL_IRD_INSTANCE}/${THE_SECOND_IRD_RESOURCE_ID}
+
+Add one IRD configuration entry in one IRD instance
+ [Documentation] Add one IRD configuration entry in an IRD whose name is hello. Link IRD entry to one existed resource.
+ Wait Until Keyword Succeeds 5s 1s Add An IRD Configuration Entry ${THE_FIRST_IRD_RESOURCE_ID} ${DEFAULT_CONTEXT_ID} ${RESOURCE_IN_FIRST_IRD} ${BASE_URL}
+ Wait Until Keyword Succeeds 5s 1s Add An IRD Configuration Entry ${THE_SECOND_IRD_RESOURCE_ID} ${DEFAULT_CONTEXT_ID} ${RESOURCE_IN_SECOND_IRD} ${BASE_URL}
+
+*** Keywords ***
+Check GET Response Code Equals 200
+ [Arguments] ${uri_without_ip_port}
+ ${resp} RequestsLibrary.Get Request session ${uri_without_ip_port}
+ Should Be Equal As Strings ${resp.status_code} 200
+
+Create An IRD
+ [Arguments] ${context_id} ${IRD_id}
+ ${body} Set Variable {"ird-instance-configuration":{"entry-context":"/alto-resourcepool:context[alto-resourcepool:context-id='${context_id}']","instance-id":"${IRD_id}"}}
+ ${resp} RequestsLibrary.Put Request session /${ALTO_CONFIG_IRD_INSTANCE_CONFIG}/${IRD_id} data=${body}
+ Should Be Equal As Strings ${resp.status_code} 200
+
+Add An IRD Configuration Entry
+ [Arguments] ${IRD_id} ${context_id} ${resource_id} ${base_url}
+ ${body} Set Variable {"ird-configuration-entry":{"entry-id":"${resource_id}","instance":"/alto-resourcepool:context[alto-resourcepool:context-id='${context_id}']/alto-resourcepool:resource[alto-resourcepool:resource-id='${resource_id}']","path":"${base_url}/${resource_id}"}}
+ ${resp} RequestsLibrary.Put Request session /${ALTO_CONFIG_IRD_INSTANCE_CONFIG}/${IRD_id}/ird-configuration-entry/${resource_id} data=${body}
+ should Be Equal As Strings ${resp.status_code} 200