Add integration tests for ALTO project.
[integration/test.git] / csit / libraries / ALTO / AltoParser.py
1 """
2 Library for ALTO project robot system test framework.
3 Author: linxiao9292@outlook.com
4 """
5
6 import json
7 import re
8
9 content_key_set = {"meta", "resources"}
10 resource_key_set = {"uri", "media-type", "accepts", "capabilities", "uses"}
11 cost_type_key_set = {"cost-mode", "cost-metric", "description"}
12 media_type_set = {"application/alto-directory+json",
13                   "application/alto-networkmap+json",
14                   "application/alto-networkmapfilter+json",
15                   "application/alto-costmap+json",
16                   "application/alto-costmapfilter+json",
17                   "application/alto-endpointprop+json",
18                   "application/alto-endpointpropparams+json",
19                   "application/alto-endpointcost+json",
20                   "application/alto-endpointcostparams+json",
21                   "application/alto-error+json"
22                   }
23
24
25 def get_basic_info(response):
26     """Get basic information of the simple IRD.
27
28     Args:
29         :param response: response from restconf/operational/alto-simple-ird:information
30             contains context-id and base-url for alto-simple-ird.
31     Returns:
32         :returns tuple: context-id - Identifier of different implementations of one service.
33             The formation of it is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
34             For example, we have three implementations of IRD service, and we could use
35             different context-id to identify them.
36
37                         base-url - ALTO northbound URL of simple IRD.
38     """
39     resp = json.loads(response)
40     return resp["information"]["context-id"], resp["information"]["base-url"]
41
42
43 def check_ird_configuration_entry(response, ird_resource_id, context_id, resource_id):
44     """Check whether resources we added are in the resource pool.
45
46     Args:
47         :param response: response from restconf/operational/alto-resourcepool:context/context-id
48             context-id is from get_basic_info(response).
49
50         :param ird_resource_id: ID of the IRD.
51
52         :param context_id: See above.
53
54         :param resource_id: ID of the resource.
55             context-id and resource-id together could determine one implementation of one service.
56     Returns:
57         :return bool: False if we do not get the resource we added before
58     """
59     resp = json.loads(response)
60     resources = resp["context"][0]["resource"]
61     for resource in resources:
62         if resource["resource-id"] == ird_resource_id:
63             context_tags = resource["context-tag"]
64             for tag in context_tags:
65                 if "dependency" in tag:
66                     for one_dependency in tag["dependency"]:
67                         _context_id = re.findall("\d{8}-\d{4}-\d{4}-\d{4}-\d{12}", one_dependency)[0]
68                         if _context_id == context_id:
69                             long_resource_id = re.findall("resource-id='[a-zA-Z\-]*'", one_dependency)[0]
70                             short_resource_id = re.findall("'.*'", long_resource_id)[0]
71                             _resource_id = short_resource_id.replace("'", "")
72                             if _resource_id == resource_id:
73                                 return True
74     return False
75
76
77 def verify_ird(response):
78     """Semantic check of IRD response, more information in RFC 7285 9.2.
79
80     Args:
81         :param response: response from ALTO northbound URL of IRD.
82     Returns:
83         :return: bool: False if there are some semantic errors.
84             One semantic error is that we only define routing-cost in cost-type, but we find that one capability of a
85             resource is bandwidth.
86     """
87     if response.headers["content-type"] != "application/alto-directory+json":
88         return False
89     try:
90         resp = json.loads(response.content)
91     except ValueError:
92         return False
93     if "meta" not in resp:
94         return False
95     meta = resp["meta"]
96     if "cost-types" in meta:
97         cost_types = meta["cost-types"]
98         for cost_type in cost_types:
99             if set(cost_type).issubset(cost_type_key_set):
100                 if "cost-mode" in cost_type and "cost-metric" in cost_type:
101                     continue
102                 else:
103                     return False
104             else:
105                 return False
106
107     resources = resp["resources"]
108     for resource in resources.keys():
109         if set(resources[resource].keys()).issubset(resource_key_set):
110             if "uri" not in resources[resource] or "media-type" not in resources[resource]:
111                 return False
112             else:
113                 _resource = resources[resource]
114                 media_type = _resource["media-type"]
115                 if media_type not in media_type_set:
116                     return False
117                 if "capabilities" in _resource:
118                     capabilities = _resource["capabilities"]
119                     if "cost-type-names" in capabilities:
120                         cost_type_names = capabilities["cost-type-names"]
121                         for cost_type_name in cost_type_names:
122                             if cost_type_name not in cost_types:
123                                 return False
124         else:
125             return False
126     return True