2 ##############################################################################
3 # Copyright (c) 2017 Orange, Inc. and others. All rights reserved.
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 ##############################################################################
23 class TransportPCEtesting(unittest.TestCase):
26 simple_topo_bi_dir_data = None
27 simple_topo_uni_dir_data = None
28 complex_topo_uni_dir_data = None
29 restconf_baseurl = "http://localhost:8181/restconf"
33 topo_bi_dir_file = os.path.join(os.path.dirname(os.path.realpath(__file__)),
34 "..", "..", "sample_configs", "honeynode-topo.xml")
35 if os.path.isfile(topo_bi_dir_file):
36 with open(topo_bi_dir_file, 'r') as topo_bi_dir:
37 cls.simple_topo_bi_dir_data = topo_bi_dir.read()
38 topo_uni_dir_file = os.path.join(os.path.dirname(os.path.realpath(__file__)),
39 "..", "..", "sample_configs", "NW-simple-topology.xml")
40 if os.path.isfile(topo_uni_dir_file):
41 with open(topo_uni_dir_file, 'r') as topo_uni_dir:
42 cls.simple_topo_uni_dir_data = topo_uni_dir.read()
43 topo_uni_dir_complex_file = os.path.join(os.path.dirname(os.path.realpath(__file__)),
44 "..", "..", "sample_configs", "NW-for-test-5-4.xml")
45 if os.path.isfile(topo_uni_dir_complex_file):
46 with open(topo_uni_dir_complex_file, 'r') as topo_uni_dir_complex:
47 cls.complex_topo_uni_dir_data = topo_uni_dir_complex.read()
50 def setUpClass(cls): # a class method called before tests in an individual class run.
52 cls.odl_process = test_utils.start_tpce()
54 print("opendaylight started")
57 def tearDownClass(cls):
58 for child in psutil.Process(cls.odl_process.pid).children():
59 child.send_signal(signal.SIGINT)
61 cls.odl_process.send_signal(signal.SIGINT)
62 cls.odl_process.wait()
64 def setUp(self): # instruction executed before each test method
67 # Load simple bidirectional topology
68 def test_01_load_simple_topology_bi(self):
69 url = ("{}/config/ietf-network:networks/network/openroadm-topology"
70 .format(self.restconf_baseurl))
71 body = self.simple_topo_bi_dir_data
72 headers = {'content-type': 'application/xml',
73 "Accept": "application/xml"}
74 response = requests.request(
75 "PUT", url, data=body, headers=headers,
76 auth=('admin', 'admin'))
77 self.assertEqual(response.status_code, requests.codes.ok)
81 def test_02_get_nodeId(self):
82 url = ("{}/config/ietf-network:networks/network/openroadm-topology/node/ROADMA01-SRG1"
83 .format(self.restconf_baseurl))
84 headers = {'content-type': 'application/json',
85 "Accept": "application/json"}
86 response = requests.request(
87 "GET", url, headers=headers, auth=('admin', 'admin'))
88 self.assertEqual(response.status_code, requests.codes.ok)
91 res['node'][0]['node-id'], 'ROADMA01-SRG1')
95 def test_03_get_linkId(self):
96 url = ("{}/config/ietf-network:networks/network/openroadm-topology/link/XPDRA01-XPDR1-XPDR1-NETWORK1toROADMA01-SRG1-SRG1-PP1-TXRX"
97 .format(self.restconf_baseurl))
98 headers = {'content-type': 'application/json',
99 "Accept": "application/json"}
100 response = requests.request(
101 "GET", url, headers=headers, auth=('admin', 'admin'))
102 self.assertEqual(response.status_code, requests.codes.ok)
103 res = response.json()
105 res['ietf-network-topology:link'][0]['link-id'],
106 'XPDRA01-XPDR1-XPDR1-NETWORK1toROADMA01-SRG1-SRG1-PP1-TXRX')
109 # Path Computation success
110 def test_04_path_computation_xpdr_bi(self):
111 url = ("{}/operations/transportpce-pce:path-computation-request"
112 .format(self.restconf_baseurl))
114 "service-name": "service-1",
115 "resource-reserve": "true",
116 "pce-metric": "hop-count",
117 "service-handler-header": {
118 "request-id": "request-1"
121 "node-id": "XPDRA01",
122 "service-rate": "100",
123 "service-format": "Ethernet",
127 "node-id": "XPDRC01",
128 "service-rate": "100",
129 "service-format": "Ethernet",
134 headers = {'content-type': 'application/json',
135 "Accept": "application/json"}
136 response = requests.request(
137 "POST", url, data=json.dumps(body), headers=headers,
138 auth=('admin', 'admin'))
139 self.assertEqual(response.status_code, requests.codes.ok)
140 res = response.json()
141 self.assertIn('Path is calculated',
142 res['output']['configuration-response-common']['response-message'])
145 # Path Computation success
146 def test_05_path_computation_rdm_bi(self):
147 url = ("{}/operations/transportpce-pce:path-computation-request"
148 .format(self.restconf_baseurl))
150 "service-name": "service-1",
151 "resource-reserve": "true",
152 "pce-metric": "hop-count",
153 "service-handler-header": {
154 "request-id": "request-1"
157 "node-id": "ROADMA01",
158 "service-rate": "100",
159 "service-format": "Ethernet",
163 "node-id": "ROADMC01",
164 "service-rate": "100",
165 "service-format": "Ethernet",
170 headers = {'content-type': 'application/json',
171 "Accept": "application/json"}
172 response = requests.request(
173 "POST", url, data=json.dumps(body), headers=headers,
174 auth=('admin', 'admin'))
175 self.assertEqual(response.status_code, requests.codes.ok)
176 res = response.json()
177 self.assertIn('Path is calculated',
178 res['output']['configuration-response-common']['response-message'])
182 def test_06_delete_simple_topology_bi(self):
183 url = ("{}/config/ietf-network:networks/network/openroadm-topology"
184 .format(self.restconf_baseurl))
185 headers = {'content-type': 'application/xml',
186 "Accept": "application/json"}
187 response = requests.request(
188 "DELETE", url, headers=headers, auth=('admin', 'admin'))
189 self.assertEqual(response.status_code, requests.codes.ok)
192 # Test deleted topology
193 def test_07_test_topology_simple_bi_deleted(self):
194 url = ("{}/config/ietf-network:networks/network/openroadm-topology/node/ROADMA01-SRG1"
195 .format(self.restconf_baseurl))
196 headers = {'content-type': 'application/json',
197 "Accept": "application/json"}
198 response = requests.request(
199 "GET", url, headers=headers, auth=('admin', 'admin'))
200 self.assertEqual(response.status_code, 404)
203 # Load simple bidirectional topology
204 def test_08_load_simple_topology_uni(self):
205 url = ("{}/config/ietf-network:networks/network/openroadm-topology"
206 .format(self.restconf_baseurl))
207 body = self.simple_topo_uni_dir_data
208 headers = {'content-type': 'application/xml',
209 "Accept": "application/xml"}
210 response = requests.request(
211 "PUT", url, data=body, headers=headers,
212 auth=('admin', 'admin'))
213 self.assertEqual(response.status_code, 201)
216 # Get existing nodeId
217 def test_09_get_nodeId(self):
218 url = ("{}/config/ietf-network:networks/network/openroadm-topology/node/XPONDER-1-2"
219 .format(self.restconf_baseurl))
220 headers = {'content-type': 'application/json',
221 "Accept": "application/json"}
222 response = requests.request(
223 "GET", url, headers=headers, auth=('admin', 'admin'))
224 self.assertEqual(response.status_code, requests.codes.ok)
225 res = response.json()
227 res['node'][0]['node-id'],
231 # Get existing linkId
232 def test_10_get_linkId(self):
233 url = ("{}/config/ietf-network:networks/network/openroadm-topology/link/XPONDER-1-2XPDR-NW1-TX-toOpenROADM-1-2-SRG1-SRG1-PP1-RX"
234 .format(self.restconf_baseurl))
235 headers = {'content-type': 'application/json',
236 "Accept": "application/json"}
237 response = requests.request(
238 "GET", url, headers=headers, auth=('admin', 'admin'))
239 self.assertEqual(response.status_code, requests.codes.ok)
240 res = response.json()
242 res['ietf-network-topology:link'][0]['link-id'],
243 'XPONDER-1-2XPDR-NW1-TX-toOpenROADM-1-2-SRG1-SRG1-PP1-RX')
246 # Path Computation success
247 def test_11_path_computation_xpdr_uni(self):
248 url = ("{}/operations/transportpce-pce:path-computation-request"
249 .format(self.restconf_baseurl))
251 "service-name": "service-1",
252 "resource-reserve": "true",
253 "pce-metric": "hop-count",
254 "service-handler-header": {
255 "request-id": "request-1"
258 "node-id": "XPONDER-1-2",
259 "service-rate": "100",
260 "service-format": "Ethernet",
264 "node-id": "XPONDER-3-2",
265 "service-rate": "100",
266 "service-format": "Ethernet",
271 headers = {'content-type': 'application/json',
272 "Accept": "application/json"}
273 response = requests.request(
274 "POST", url, data=json.dumps(body), headers=headers,
275 auth=('admin', 'admin'))
276 self.assertEqual(response.status_code, requests.codes.ok)
277 res = response.json()
278 self.assertIn('Path is calculated',
279 res['output']['configuration-response-common']['response-message'])
282 # Path Computation success
283 def test_12_path_computation_rdm_uni(self):
284 url = ("{}/operations/transportpce-pce:path-computation-request"
285 .format(self.restconf_baseurl))
287 "service-name": "service1",
288 "resource-reserve": "true",
289 "service-handler-header": {
290 "request-id": "request1"
293 "service-rate": "100",
294 "service-format": "Ethernet",
296 "node-id": "OpenROADM-2-1"
299 "service-rate": "100",
300 "service-format": "Ethernet",
302 "node-id": "OpenROADM-2-2"
304 "pce-metric": "hop-count"
307 headers = {'content-type': 'application/json',
308 "Accept": "application/json"}
309 response = requests.request(
310 "POST", url, data=json.dumps(body), headers=headers,
311 auth=('admin', 'admin'))
312 self.assertEqual(response.status_code, requests.codes.ok)
313 res = response.json()
314 self.assertIn('Path is calculated',
315 res['output']['configuration-response-common']['response-message'])
317 atozList = len(res['output']['response-parameters']['path-description']['aToZ-direction']['aToZ'])
318 ztoaList = len(res['output']['response-parameters']['path-description']['zToA-direction']['zToA'])
319 self.assertEqual(atozList, 15)
320 self.assertEqual(ztoaList, 15)
321 for i in range(0, 15):
322 atoz = res['output']['response-parameters']['path-description']['aToZ-direction']['aToZ'][i]
323 ztoa = res['output']['response-parameters']['path-description']['zToA-direction']['zToA'][i]
324 if (atoz['id'] == '14'):
325 self.assertEqual(atoz['resource']['tp-id'], 'SRG1-PP1-TX')
326 if (ztoa['id'] == '0'):
327 self.assertEqual(ztoa['resource']['tp-id'], 'SRG1-PP1-RX')
331 def test_13_delete_simple_topology(self):
332 url = ("{}/config/ietf-network:networks/network/openroadm-topology"
333 .format(self.restconf_baseurl))
334 headers = {'content-type': 'application/xml',
335 "Accept": "application/json"}
336 response = requests.request(
337 "DELETE", url, headers=headers, auth=('admin', 'admin'))
338 self.assertEqual(response.status_code, requests.codes.ok)
341 # Test deleted topology
342 def test_14_test_topology_simple_deleted(self):
343 url = ("{}/config/ietf-network:networks/network/openroadm-topology/node/XPONDER-1-2"
344 .format(self.restconf_baseurl))
345 headers = {'content-type': 'application/json',
346 "Accept": "application/json"}
347 response = requests.request(
348 "GET", url, headers=headers, auth=('admin', 'admin'))
349 self.assertEqual(response.status_code, 404)
352 # Load complex topology
353 def test_15_load_complex_topology(self):
354 url = ("{}/config/ietf-network:networks/network/openroadm-topology"
355 .format(self.restconf_baseurl))
356 body = self.complex_topo_uni_dir_data
357 headers = {'content-type': 'application/xml',
358 "Accept": "application/json"}
359 response = requests.request(
360 "PUT", url, data=body, headers=headers,
361 auth=('admin', 'admin'))
362 self.assertEqual(response.status_code, 201)
365 # Get existing nodeId
366 def test_16_get_nodeId(self):
367 url = ("{}/config/ietf-network:networks/network/openroadm-topology/node/XPONDER-3-2"
368 .format(self.restconf_baseurl))
369 headers = {'content-type': 'application/json',
370 "Accept": "application/json"}
371 response = requests.request(
372 "GET", url, headers=headers, auth=('admin', 'admin'))
373 self.assertEqual(response.status_code, requests.codes.ok)
374 res = response.json()
376 res['node'][0]['node-id'],
380 # Test failed path computation
381 def test_17_fail_path_computation(self):
382 url = ("{}/operations/transportpce-pce:path-computation-request"
383 .format(self.restconf_baseurl))
385 "service-handler-header": {
386 "request-id": "request-1"
390 headers = {'content-type': 'application/json',
391 "Accept": "application/json"}
392 response = requests.request(
393 "POST", url, data=json.dumps(body), headers=headers,
394 auth=('admin', 'admin'))
395 self.assertEqual(response.status_code, requests.codes.ok)
396 res = response.json()
397 self.assertIn('Service Name is not set',
398 res['output']['configuration-response-common']['response-message'])
401 # Test1 success path computation
402 def test_18_success1_path_computation(self):
403 url = ("{}/operations/transportpce-pce:path-computation-request"
404 .format(self.restconf_baseurl))
406 "service-name": "service1",
407 "resource-reserve": "true",
408 "service-handler-header": {
409 "request-id": "request1"
412 "service-format": "Ethernet",
413 "service-rate": "100",
415 "node-id": "XPONDER-2-2",
418 "port-device-name": "Some port-device-name",
419 "port-type": "Some port-type",
420 "port-name": "Some port-name",
421 "port-rack": "Some port-rack",
422 "port-shelf": "Some port-shelf",
423 "port-slot": "Some port-slot",
424 "port-sub-slot": "Some port-sub-slot"
429 "port-device-name": "Some port-device-name",
430 "port-type": "Some port-type",
431 "port-name": "Some port-name",
432 "port-rack": "Some port-rack",
433 "port-shelf": "Some port-shelf",
434 "port-slot": "Some port-slot",
435 "port-sub-slot": "Some port-sub-slot"
440 "service-format": "Ethernet",
441 "service-rate": "100",
443 "node-id": "XPONDER-1-2",
446 "port-device-name": "Some port-device-name",
447 "port-type": "Some port-type",
448 "port-name": "Some port-name",
449 "port-rack": "Some port-rack",
450 "port-shelf": "Some port-shelf",
451 "port-slot": "Some port-slot",
452 "port-sub-slot": "Some port-sub-slot"
457 "port-device-name": "Some port-device-name",
458 "port-type": "Some port-type",
459 "port-name": "Some port-name",
460 "port-rack": "Some port-rack",
461 "port-shelf": "Some port-shelf",
462 "port-slot": "Some port-slot",
463 "port-sub-slot": "Some port-sub-slot"
467 "hard-constraints": {
472 "existing-service": [
473 "Some existing-service"
477 "soft-constraints": {
482 "existing-service": [
483 "Some existing-service"
487 "pce-metric": "hop-count",
488 "locally-protected-links": "true"
491 headers = {'content-type': 'application/json',
492 "Accept": "application/json"}
493 response = requests.request(
494 "POST", url, data=json.dumps(body), headers=headers,
495 auth=('admin', 'admin'))
496 self.assertEqual(response.status_code, requests.codes.ok)
497 res = response.json()
498 self.assertIn('Path is calculated',
499 res['output']['configuration-response-common']['response-message'])
502 # Test2 success path computation with path description
503 def test_19_success2_path_computation(self):
504 url = ("{}/operations/transportpce-pce:path-computation-request"
505 .format(self.restconf_baseurl))
507 "service-name": "service 1",
508 "resource-reserve": "true",
509 "service-handler-header": {
510 "request-id": "request 1"
513 "service-rate": "100",
514 "service-format": "Ethernet",
515 "node-id": "XPONDER-1-2",
519 "service-rate": "100",
520 "service-format": "Ethernet",
521 "node-id": "XPONDER-3-2",
524 "pce-metric": "hop-count"
527 headers = {'content-type': 'application/json',
528 "Accept": "application/json"}
529 response = requests.request(
530 "POST", url, data=json.dumps(body), headers=headers,
531 auth=('admin', 'admin'))
532 self.assertEqual(response.status_code, requests.codes.ok)
533 res = response.json()
534 self.assertIn('Path is calculated',
535 res['output']['configuration-response-common']['response-message'])
536 self.assertEqual(5, res['output']['response-parameters']['path-description']
537 ['aToZ-direction']['aToZ-wavelength-number'])
538 self.assertEqual(5, res['output']['response-parameters']['path-description']
539 ['zToA-direction']['zToA-wavelength-number'])
542 # Test3 success path computation with hard-constraints exclude
543 def test_20_success3_path_computation(self):
544 url = ("{}/operations/transportpce-pce:path-computation-request"
545 .format(self.restconf_baseurl))
547 "service-name": "service 1",
548 "resource-reserve": "true",
549 "service-handler-header": {
550 "request-id": "request 1"
553 "service-rate": "100",
554 "service-format": "Ethernet",
555 "node-id": "XPONDER-1-2",
559 "service-rate": "100",
560 "service-format": "Ethernet",
561 "node-id": "XPONDER-3-2",
564 "hard-constraints": {
566 "node-id": ["OpenROADM-2-1", "OpenROADM-2-2"]
569 "pce-metric": "hop-count"
572 headers = {'content-type': 'application/json',
573 "Accept": "application/json"}
574 response = requests.request(
575 "POST", url, data=json.dumps(body), headers=headers,
576 auth=('admin', 'admin'))
577 self.assertEqual(response.status_code, requests.codes.ok)
578 res = response.json()
579 self.assertIn('Path is calculated',
580 res['output']['configuration-response-common']['response-message'])
581 self.assertEqual(9, res['output']['response-parameters']['path-description']
582 ['aToZ-direction']['aToZ-wavelength-number'])
583 self.assertEqual(9, res['output']['response-parameters']['path-description']
584 ['zToA-direction']['zToA-wavelength-number'])
587 # Path computation before deleting oms-attribute of the link :openroadm1-3 to openroadm1-2
588 def test_21_path_computation_before_oms_attribute_deletion(self):
589 url = ("{}/operations/transportpce-pce:path-computation-request"
590 .format(self.restconf_baseurl))
592 "service-name": "service 1",
593 "resource-reserve": "true",
594 "service-handler-header": {
595 "request-id": "request 1"
598 "service-rate": "100",
599 "service-format": "Ethernet",
600 "node-id": "XPONDER-2-2",
604 "service-rate": "100",
605 "service-format": "Ethernet",
606 "node-id": "XPONDER-1-2",
609 "pce-metric": "hop-count"
612 headers = {'content-type': 'application/json',
613 "Accept": "application/json"}
614 response = requests.request(
615 "POST", url, data=json.dumps(body), headers=headers,
616 auth=('admin', 'admin'))
617 self.assertEqual(response.status_code, requests.codes.ok)
618 res = response.json()
619 self.assertIn('Path is calculated',
620 res['output']['configuration-response-common']['response-message'])
621 nbElmPath = len(res['output']['response-parameters']['path-description']
622 ['aToZ-direction']['aToZ'])
623 self.assertEqual(31, nbElmPath)
624 link = {"link-id": "OpenROADM-1-3-DEG2-to-OpenROADM-1-2-DEG2"}
626 for i in range(0, nbElmPath):
627 resource_i = res['output']['response-parameters']['path-description']['aToZ-direction']['aToZ'][i]['resource']
628 if(resource_i == link):
630 self.assertEqual(find, True)
633 # Delete oms-attribute in the link :openroadm1-3 to openroadm1-2
634 def test_22_delete_oms_attribute_in_openroadm13toopenroadm12_link(self):
635 url = ("{}/config/ietf-network:networks/network/openroadm-topology/ietf-network-topology:link/"
636 "OpenROADM-1-3-DEG2-to-OpenROADM-1-2-DEG2/org-openroadm-network-topology:OMS-attributes/span"
637 .format(self.restconf_baseurl))
638 headers = {'content-type': 'application/xml',
639 "Accept": "application/json"}
640 response = requests.request(
641 "DELETE", url, headers=headers, auth=('admin', 'admin'))
642 self.assertEqual(response.status_code, requests.codes.ok)
645 # Path computation after deleting oms-attribute of the link :openroadm1-3 to openroadm1-2
646 def test_23_path_computation_after_oms_attribute_deletion(self):
647 url = ("{}/operations/transportpce-pce:path-computation-request"
648 .format(self.restconf_baseurl))
650 "service-name": "service 1",
651 "resource-reserve": "true",
652 "service-handler-header": {
653 "request-id": "request 1"
656 "service-rate": "100",
657 "service-format": "Ethernet",
658 "node-id": "XPONDER-2-2",
662 "service-rate": "100",
663 "service-format": "Ethernet",
664 "node-id": "XPONDER-1-2",
667 "pce-metric": "hop-count"
670 headers = {'content-type': 'application/json',
671 "Accept": "application/json"}
672 response = requests.request(
673 "POST", url, data=json.dumps(body), headers=headers,
674 auth=('admin', 'admin'))
675 self.assertEqual(response.status_code, requests.codes.ok)
676 res = response.json()
677 self.assertIn('Path is calculated',
678 res['output']['configuration-response-common']['response-message'])
679 nbElmPath = len(res['output']['response-parameters']['path-description']
680 ['aToZ-direction']['aToZ'])
681 self.assertEqual(47, nbElmPath)
682 link = {"link-id": "OpenROADM-1-3-DEG2-to-OpenROADM-1-2-DEG2"}
684 for i in range(0, nbElmPath):
685 resource_i = res['output']['response-parameters']['path-description']['aToZ-direction']['aToZ'][i]['resource']
686 if (resource_i == link):
688 self.assertNotEqual(find, True)
691 # Delete complex topology
692 def test_24_delete_complex_topology(self):
693 url = ("{}/config/ietf-network:networks/network/openroadm-topology"
694 .format(self.restconf_baseurl))
695 headers = {'content-type': 'application/xml',
696 "Accept": "application/json"}
697 response = requests.request(
698 "DELETE", url, headers=headers, auth=('admin', 'admin'))
699 self.assertEqual(response.status_code, requests.codes.ok)
702 # Test deleted complex topology
703 def test_25_test_topology_complex_deleted(self):
704 url = ("{}/config/ietf-network:networks/network/openroadm-topology/node/XPONDER-3-2"
705 .format(self.restconf_baseurl))
706 headers = {'content-type': 'application/json',
707 "Accept": "application/json"}
708 response = requests.request(
709 "GET", url, headers=headers, auth=('admin', 'admin'))
710 self.assertEqual(response.status_code, 404)
714 if __name__ == "__main__":
715 unittest.main(verbosity=2)