fix minor bugs in portmapping
[transportpce.git] / tests / transportpce_tests / test_pce.py
1 #!/usr/bin/env python
2 ##############################################################################
3 # Copyright (c) 2017 Orange, Inc. and others.  All rights reserved.
4 #
5 # All rights reserved. This program and the accompanying materials
6 # are made available under the terms of the Apache License, Version 2.0
7 # which accompanies this distribution, and is available at
8 # http://www.apache.org/licenses/LICENSE-2.0
9 ##############################################################################
10
11 import json
12 import os
13 import psutil
14 import requests
15 import signal
16 import shutil
17 import subprocess
18 import time
19 import unittest
20
21
22 class TransportPCEtesting(unittest.TestCase):
23
24     odl_process = None
25     simple_topo_bi_dir_data = None
26     simple_topo_uni_dir_data = None
27     complex_topo_uni_dir_data = None
28     restconf_baseurl = "http://localhost:8181/restconf"
29
30     @classmethod
31     def _get_file(cls):
32         topo_bi_dir_file = "sample_configs/honeynode-topo.xml"
33         if os.path.isfile(topo_bi_dir_file):
34             with open(topo_bi_dir_file, 'r') as topo_bi_dir:
35                 cls.simple_topo_bi_dir_data = topo_bi_dir.read();
36         topo_uni_dir_file = "sample_configs/NW-simple-topology.xml"
37         if os.path.isfile(topo_uni_dir_file):
38             with open(topo_uni_dir_file, 'r') as topo_uni_dir:
39                 cls.simple_topo_uni_dir_data = topo_uni_dir.read();
40         topo_uni_dir_complex_file = "sample_configs/NW-for-test-5-4.xml"
41         if os.path.isfile(topo_uni_dir_complex_file):
42             with open(topo_uni_dir_complex_file, 'r') as topo_uni_dir_complex:
43                 cls.complex_topo_uni_dir_data = topo_uni_dir_complex.read();
44
45     @classmethod
46     def __start_odl(cls):
47         executable = "../karaf/target/assembly/bin/karaf"
48         with open('odl.log', 'w') as outfile:
49             cls.odl_process = subprocess.Popen(
50                 ["bash", executable, "server"], stdout=outfile,
51                 stdin=open(os.devnull))
52
53     @classmethod
54     def setUpClass(cls):  # a class method called before tests in an individual class run.
55         cls._get_file()
56         cls.__start_odl()
57         time.sleep(90)
58
59     @classmethod
60     def tearDownClass(cls):
61         for child in psutil.Process(cls.odl_process.pid).children():
62             child.send_signal(signal.SIGINT)
63             child.wait()
64         cls.odl_process.send_signal(signal.SIGINT)
65         cls.odl_process.wait()
66
67     def setUp(self):  # instruction executed before each test method
68         time.sleep(1)
69
70      # Load simple bidirectional topology
71     def test_01_load_simple_topology_bi(self):
72         url = ("{}/config/ietf-network:network/openroadm-topology"
73               .format(self.restconf_baseurl))
74         body = self.simple_topo_bi_dir_data
75         headers = {'content-type': 'application/xml',
76         "Accept": "application/json"}
77         response = requests.request(
78             "PUT", url, data=body, headers=headers,
79             auth=('admin', 'admin'))
80         self.assertEqual(response.status_code, requests.codes.ok)
81         time.sleep(2)
82
83     # Get existing nodeId
84     def test_02_get_nodeId(self):
85         url = ("{}/config/ietf-network:network/openroadm-topology/node/ROADMA-SRG1"
86                 .format(self.restconf_baseurl))
87         headers = {'content-type': 'application/json',
88         "Accept": "application/json"}
89         response = requests.request(
90             "GET", url, headers=headers, auth=('admin', 'admin'))
91         self.assertEqual(response.status_code, requests.codes.ok)
92         res = response.json()
93         self.assertEqual(
94             res['node'][0]['node-id'], 'ROADMA-SRG1')
95         time.sleep(1)
96
97     # Get existing linkId
98     def test_03_get_linkId(self):
99         url = ("{}/config/ietf-network:network/openroadm-topology/link/XPDRA-XPDR1-XPDR1-NETWORK1toROADMA-SRG1-SRG1-PP1-TXRX"
100               .format(self.restconf_baseurl))
101         headers = {'content-type': 'application/json',
102         "Accept": "application/json"}
103         response = requests.request(
104             "GET", url, headers=headers, auth=('admin', 'admin'))
105         self.assertEqual(response.status_code, requests.codes.ok)
106         res = response.json()
107         self.assertEqual(
108             res['ietf-network-topology:link'][0]['link-id'],
109             'XPDRA-XPDR1-XPDR1-NETWORK1toROADMA-SRG1-SRG1-PP1-TXRX')
110         time.sleep(1)
111
112     # Path Computation success
113     def test_04_path_computation_xpdr_bi(self):
114         url = ("{}/operations/transportpce-pce:path-computation-request"
115               .format(self.restconf_baseurl))
116         body = {"input": {
117                 "service-name": "service-1",
118                 "resource-reserve": "true",
119                 "pce-metric": "hop-count",
120                 "service-handler-header": {
121                     "request-id": "request-1"
122                 },
123                 "service-a-end": {
124                     "node-id": "XPDRA",
125                     "service-rate": "0",
126                     "clli": "nodeA"
127                 },
128                 "service-z-end": {
129                     "node-id": "XPDRC",
130                     "service-rate": "0",
131                     "clli": "nodeC"
132                 }
133             }
134         }
135         headers = {'content-type': 'application/json',
136         "Accept": "application/json"}
137         response = requests.request(
138             "POST", url, data=json.dumps(body), headers=headers,
139             auth=('admin', 'admin'))
140         self.assertEqual(response.status_code, requests.codes.ok)
141         res = response.json()
142         self.assertIn('Path is calculated',
143             res['output']['configuration-response-common']['response-message'])
144         time.sleep(5)
145
146     # Path Computation success
147     def test_05_path_computation_rdm_bi(self):
148         url = ("{}/operations/transportpce-pce:path-computation-request"
149               .format(self.restconf_baseurl))
150         body = {"input": {
151                 "service-name": "service-1",
152                 "resource-reserve": "true",
153                 "pce-metric": "hop-count",
154                 "service-handler-header": {
155                     "request-id": "request-1"
156                 },
157                 "service-a-end": {
158                     "node-id": "ROADMA",
159                     "service-rate": "0",
160                     "clli": "nodeA"
161                 },
162                 "service-z-end": {
163                     "node-id": "ROADMC",
164                     "service-rate": "0",
165                     "clli": "nodeC"
166                 }
167             }
168         }
169         headers = {'content-type': 'application/json',
170         "Accept": "application/json"}
171         response = requests.request(
172             "POST", url, data=json.dumps(body), headers=headers,
173             auth=('admin', 'admin'))
174         self.assertEqual(response.status_code, requests.codes.ok)
175         res = response.json()
176         self.assertIn('Path is calculated',
177             res['output']['configuration-response-common']['response-message'])
178         time.sleep(5)
179
180     # Delete topology
181     def test_06_delete_simple_topology_bi(self):
182         url = ("{}/config/ietf-network:network/openroadm-topology"
183               .format(self.restconf_baseurl))
184         headers = {'content-type': 'application/xml',
185         "Accept": "application/json"}
186         response = requests.request(
187             "DELETE", url, headers=headers, auth=('admin', 'admin'))
188         self.assertEqual(response.status_code, requests.codes.ok)
189         time.sleep(2)
190
191     # Test deleted topology
192     def test_07_test_topology_simple_bi_deleted(self):
193         url = ("{}/config/ietf-network:network/openroadm-topology/node/ROADMA-SRG1"
194                 .format(self.restconf_baseurl))
195         headers = {'content-type': 'application/json',
196         "Accept": "application/json"}
197         response = requests.request(
198             "GET", url, headers=headers, auth=('admin', 'admin'))
199         self.assertEqual(response.status_code, 404)
200         time.sleep(1)
201
202     # Load simple bidirectional topology
203     def test_08_load_simple_topology_uni(self):
204         url = ("{}/config/ietf-network:network/openroadm-topology"
205               .format(self.restconf_baseurl))
206         body = self.simple_topo_uni_dir_data
207         headers = {'content-type': 'application/xml',
208         "Accept": "application/json"}
209         response = requests.request(
210             "PUT", url, data=body, headers=headers,
211             auth=('admin', 'admin'))
212         self.assertEqual(response.status_code, 201)
213         time.sleep(2)
214
215     # Get existing nodeId
216     def test_09_get_nodeId(self):
217         url = ("{}/config/ietf-network:network/openroadm-topology/node/XPONDER-1-2"
218                 .format(self.restconf_baseurl))
219         headers = {'content-type': 'application/json',
220         "Accept": "application/json"}
221         response = requests.request(
222             "GET", url, headers=headers, auth=('admin', 'admin'))
223         self.assertEqual(response.status_code, requests.codes.ok)
224         res = response.json()
225         self.assertEqual(
226             res['node'][0]['node-id'],
227             'XPONDER-1-2')
228         time.sleep(1)
229
230     # Get existing linkId
231     def test_10_get_linkId(self):
232         url = ("{}/config/ietf-network:network/openroadm-topology/link/XPONDER-1-2XPDR-NW1-TX-toOpenROADM-1-2-SRG1-SRG1-PP1-RX"
233               .format(self.restconf_baseurl))
234         headers = {'content-type': 'application/json',
235         "Accept": "application/json"}
236         response = requests.request(
237             "GET", url, headers=headers, auth=('admin', 'admin'))
238         self.assertEqual(response.status_code, requests.codes.ok)
239         res = response.json()
240         self.assertEqual(
241             res['ietf-network-topology:link'][0]['link-id'],
242             'XPONDER-1-2XPDR-NW1-TX-toOpenROADM-1-2-SRG1-SRG1-PP1-RX')
243         time.sleep(1)
244
245     # Path Computation success
246     def test_11_path_computation_xpdr_uni(self):
247         url = ("{}/operations/transportpce-pce:path-computation-request"
248               .format(self.restconf_baseurl))
249         body = {"input": {
250                 "service-name": "service-1",
251                 "resource-reserve": "true",
252                 "pce-metric": "hop-count",
253                 "service-handler-header": {
254                     "request-id": "request-1"
255                 },
256                 "service-a-end": {
257                     "node-id": "XPONDER-1-2",
258                     "service-rate": "0",
259                     "clli": "ORANGE1"
260                 },
261                 "service-z-end": {
262                     "node-id": "XPONDER-3-2",
263                     "service-rate": "0",
264                     "clli": "ORANGE1"
265                 }
266             }
267         }
268         headers = {'content-type': 'application/json',
269         "Accept": "application/json"}
270         response = requests.request(
271             "POST", url, data=json.dumps(body), headers=headers,
272             auth=('admin', 'admin'))
273         self.assertEqual(response.status_code, requests.codes.ok)
274         res = response.json()
275         self.assertIn('Path is calculated',
276             res['output']['configuration-response-common']['response-message'])
277         time.sleep(5)
278
279     # Path Computation success
280     def test_12_path_computation_rdm_uni(self):
281         url = ("{}/operations/transportpce-pce:path-computation-request"
282               .format(self.restconf_baseurl))
283         body = {"input": {
284                 "service-name": "service1",
285                 "resource-reserve": "true",
286                 "service-handler-header": {
287                   "request-id": "request1"
288                 },
289                 "service-a-end": {
290                   "service-rate": "0",
291                   "clli": "cll21",
292                   "node-id": "OpenROADM-2-1"
293                 },
294                 "service-z-end": {
295                   "service-rate": "0",
296                   "clli": "ncli22",
297                   "node-id": "OpenROADM-2-2"
298                   },
299                 "pce-metric": "hop-count"
300             }
301         }
302         headers = {'content-type': 'application/json',
303         "Accept": "application/json"}
304         response = requests.request(
305             "POST", url, data=json.dumps(body), headers=headers,
306             auth=('admin', 'admin'))
307         self.assertEqual(response.status_code, requests.codes.ok)
308         res = response.json()
309         self.assertIn('Path is calculated',
310             res['output']['configuration-response-common']['response-message'])
311         #ZtoA path test
312         atozList = len(res['output']['response-parameters']['path-description']['aToZ-direction']['aToZ'])
313         ztoaList = len(res['output']['response-parameters']['path-description']['zToA-direction']['zToA'])
314         self.assertEqual(atozList,15)
315         self.assertEqual(ztoaList,15)
316         for i in range(0,15):
317             atoz = res['output']['response-parameters']['path-description']['aToZ-direction']['aToZ'][i]
318             ztoa = res['output']['response-parameters']['path-description']['zToA-direction']['zToA'][i]
319             if (atoz['id'] == '14'):
320                 self.assertEqual(atoz['resource']['tp-id'], 'SRG1-PP1-TX')
321             if (ztoa['id'] == '0'):
322                 self.assertEqual(ztoa['resource']['tp-id'], 'SRG1-PP1-RX')
323         time.sleep(5)
324
325     # Delete topology
326     def test_13_delete_simple_topology(self):
327         url = ("{}/config/ietf-network:network/openroadm-topology"
328               .format(self.restconf_baseurl))
329         headers = {'content-type': 'application/xml',
330         "Accept": "application/json"}
331         response = requests.request(
332             "DELETE", url, headers=headers, auth=('admin', 'admin'))
333         self.assertEqual(response.status_code, requests.codes.ok)
334         time.sleep(2)
335
336     # Test deleted topology
337     def test_14_test_topology_simple_deleted(self):
338         url = ("{}/config/ietf-network:network/openroadm-topology/node/XPONDER-1-2"
339                 .format(self.restconf_baseurl))
340         headers = {'content-type': 'application/json',
341         "Accept": "application/json"}
342         response = requests.request(
343             "GET", url, headers=headers, auth=('admin', 'admin'))
344         self.assertEqual(response.status_code, 404)
345         time.sleep(1)
346
347     # Load simple topology
348     def test_15_load_complex_topology(self):
349         url = ("{}/config/ietf-network:network/openroadm-topology"
350               .format(self.restconf_baseurl))
351         body = self.complex_topo_uni_dir_data
352         headers = {'content-type': 'application/xml',
353         "Accept": "application/json"}
354         response = requests.request(
355             "PUT", url, data=body, headers=headers,
356             auth=('admin', 'admin'))
357         self.assertEqual(response.status_code, 201)
358         time.sleep(2)
359
360     # Get existing nodeId
361     def test_16_get_nodeId(self):
362         url = ("{}/config/ietf-network:network/openroadm-topology/node/XPONDER-3-2"
363                 .format(self.restconf_baseurl))
364         headers = {'content-type': 'application/json',
365         "Accept": "application/json"}
366         response = requests.request(
367             "GET", url, headers=headers, auth=('admin', 'admin'))
368         self.assertEqual(response.status_code, requests.codes.ok)
369         res = response.json()
370         self.assertEqual(
371             res['node'][0]['node-id'],
372             'XPONDER-3-2')
373         time.sleep(1)
374
375     # Test failed path computation
376     def test_17_fail_path_computation(self):
377         url = ("{}/operations/transportpce-pce:path-computation-request"
378               .format(self.restconf_baseurl))
379         body = {"input": {
380                 "service-handler-header": {
381                     "request-id": "request-1"
382                 }
383             }
384         }
385         headers = {'content-type': 'application/json',
386         "Accept": "application/json"}
387         response = requests.request(
388             "POST", url, data=json.dumps(body), headers=headers,
389             auth=('admin', 'admin'))
390         self.assertEqual(response.status_code, requests.codes.ok)
391         res = response.json()
392         self.assertIn('Service Name is not set',
393             res['output']['configuration-response-common']['response-message'])
394         time.sleep(2)
395
396     # Test1 success path computation
397     def test_18_success1_path_computation(self):
398         url = ("{}/operations/transportpce-pce:path-computation-request"
399               .format(self.restconf_baseurl))
400         body = {"input": {
401                 "service-name": "service1",
402                 "resource-reserve": "true",
403                 "service-handler-header": {
404                   "request-id": "request1"
405                 },
406                 "service-a-end": {
407                   "service-format": "Ethernet",
408                   "service-rate": "0",
409                   "clli": "clli11",
410                   "node-id": "XPONDER-2-2",
411                   "tx-direction": {
412                     "port": {
413                       "port-device-name": "Some port-device-name",
414                       "port-type": "Some port-type",
415                       "port-name": "Some port-name",
416                       "port-rack": "Some port-rack",
417                       "port-shelf": "Some port-shelf",
418                       "port-slot": "Some port-slot",
419                       "port-sub-slot": "Some port-sub-slot"
420                     }
421                   },
422                   "rx-direction": {
423                     "port": {
424                       "port-device-name": "Some port-device-name",
425                       "port-type": "Some port-type",
426                       "port-name": "Some port-name",
427                       "port-rack": "Some port-rack",
428                       "port-shelf": "Some port-shelf",
429                       "port-slot": "Some port-slot",
430                       "port-sub-slot": "Some port-sub-slot"
431                     }
432                   }
433                 },
434                 "service-z-end": {
435                   "service-format": "Ethernet",
436                   "service-rate": "0",
437                   "clli": "clli11",
438                   "node-id": "XPONDER-1-2",
439                   "tx-direction": {
440                     "port": {
441                       "port-device-name": "Some port-device-name",
442                       "port-type": "Some port-type",
443                       "port-name": "Some port-name",
444                       "port-rack": "Some port-rack",
445                       "port-shelf": "Some port-shelf",
446                       "port-slot": "Some port-slot",
447                       "port-sub-slot": "Some port-sub-slot"
448                     }
449                   },
450                   "rx-direction": {
451                     "port": {
452                       "port-device-name": "Some port-device-name",
453                       "port-type": "Some port-type",
454                       "port-name": "Some port-name",
455                       "port-rack": "Some port-rack",
456                       "port-shelf": "Some port-shelf",
457                       "port-slot": "Some port-slot",
458                       "port-sub-slot": "Some port-sub-slot"
459                     }
460                   }
461                 },
462                 "hard-constraints": {
463                   "customer-code": [
464                     "Some customer-code"
465                   ],
466                   "co-routing": {
467                     "existing-service": [
468                       "Some existing-service"
469                     ]
470                   }
471                 },
472                 "soft-constraints": {
473                   "customer-code": [
474                     "Some customer-code"
475                   ],
476                   "co-routing": {
477                     "existing-service": [
478                       "Some existing-service"
479                     ]
480                   }
481                 },
482                 "pce-metric": "hop-count",
483                 "locally-protected-links": "true"
484             }
485         }
486         headers = {'content-type': 'application/json',
487         "Accept": "application/json"}
488         response = requests.request(
489             "POST", url, data=json.dumps(body), headers=headers,
490             auth=('admin', 'admin'))
491         self.assertEqual(response.status_code, requests.codes.ok)
492         res = response.json()
493         self.assertIn('Path is calculated',
494             res['output']['configuration-response-common']['response-message'])
495         time.sleep(5)
496
497     # Test2 success path computation with path description
498     def test_19_success2_path_computation(self):
499         url = ("{}/operations/transportpce-pce:path-computation-request"
500               .format(self.restconf_baseurl))
501         body = {"input": {
502                 "service-name": "service 1",
503                 "resource-reserve": "true",
504                 "service-handler-header": {
505                     "request-id": "request 1"
506                 },
507                 "service-a-end": {
508                     "service-rate": "0",
509                     "node-id": "XPONDER-1-2"
510                 },
511                 "service-z-end": {
512                     "service-rate": "0",
513                     "node-id": "XPONDER-3-2"
514              },
515              "pce-metric": "hop-count"
516            }
517         }
518         headers = {'content-type': 'application/json',
519         "Accept": "application/json"}
520         response = requests.request(
521             "POST", url, data=json.dumps(body), headers=headers,
522             auth=('admin', 'admin'))
523         self.assertEqual(response.status_code, requests.codes.ok)
524         res = response.json()
525         self.assertIn('Path is calculated',
526             res['output']['configuration-response-common']['response-message'])
527         self.assertEqual(5 , res['output']['response-parameters']['path-description']
528             ['aToZ-direction']['aToZ-wavelength-number'])
529         self.assertEqual(5 , res['output']['response-parameters']['path-description']
530             ['zToA-direction']['zToA-wavelength-number'])
531         time.sleep(5)
532
533     # Test3 success path computation with hard-constraints exclude
534     def test_20_success3_path_computation(self):
535         url = ("{}/operations/transportpce-pce:path-computation-request"
536               .format(self.restconf_baseurl))
537         body = {"input": {
538                 "service-name": "service 1",
539                 "resource-reserve": "true",
540                 "service-handler-header": {
541                     "request-id": "request 1"
542                 },
543                 "service-a-end": {
544                     "service-rate": "0",
545                     "node-id": "XPONDER-1-2"
546                 },
547                 "service-z-end": {
548                     "service-rate": "0",
549                     "node-id": "XPONDER-3-2"
550                 },
551                 "hard-constraints": {
552                     "exclude_": {
553                         "node-id": ["OpenROADM-2-1", "OpenROADM-2-2"]
554                     }
555                 },
556                 "pce-metric": "hop-count"
557             }
558         }
559         headers = {'content-type': 'application/json',
560         "Accept": "application/json"}
561         response = requests.request(
562             "POST", url, data=json.dumps(body), headers=headers,
563             auth=('admin', 'admin'))
564         self.assertEqual(response.status_code, requests.codes.ok)
565         res = response.json()
566         self.assertIn('Path is calculated',
567             res['output']['configuration-response-common']['response-message'])
568         self.assertEqual(9 , res['output']['response-parameters']['path-description']
569             ['aToZ-direction']['aToZ-wavelength-number'])
570         self.assertEqual(9 , res['output']['response-parameters']['path-description']
571             ['zToA-direction']['zToA-wavelength-number'])
572         time.sleep(5)
573
574     # Delete complex topology
575     def test_21_delete_complex_topology(self):
576         url = ("{}/config/ietf-network:network/openroadm-topology"
577               .format(self.restconf_baseurl))
578         headers = {'content-type': 'application/xml',
579         "Accept": "application/json"}
580         response = requests.request(
581             "DELETE", url, headers=headers, auth=('admin', 'admin'))
582         self.assertEqual(response.status_code, requests.codes.ok)
583         time.sleep(2)
584
585     # Test deleted complex topology
586     def test_22_test_topology_complex_deleted(self):
587         url = ("{}/config/ietf-network:network/openroadm-topology/node/XPONDER-3-2"
588                 .format(self.restconf_baseurl))
589         headers = {'content-type': 'application/json',
590         "Accept": "application/json"}
591         response = requests.request(
592             "GET", url, headers=headers, auth=('admin', 'admin'))
593         self.assertEqual(response.status_code, 404)
594         time.sleep(1)
595
596
597 if __name__ == "__main__":
598     unittest.main(verbosity=2)