1 # Copyright 2020 ArctosLabs Scandinavia AB
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
16 # pylint: disable=E1120
22 from unittest
import TestCase
, mock
23 from unittest
.mock
import Mock
27 from osm_pla
.placement
.mznplacement
import NsPlacementDataFactory
, MznPlacementConductor
28 from pathlib
import Path
30 # need to Mock the imports from osm_common made in Server and Config beforehand
31 sys
.modules
["osm_common"] = Mock()
32 from osm_pla
.server
.server
import Server
# noqa: E402
33 from osm_pla
.config
.config
import Config
# noqa: E402
35 nslcmop_record_wo_pinning
= {
36 "statusEnteredTime": 1574625718.8280587,
37 "startTime": 1574625718.8280587,
39 "created": 1574625718.8286533,
40 "projects_write": ["61e4bbab-9659-4abc-a01d-ba3a307becf9"],
41 "worker": "e5121e773e8b",
42 "modified": 1574625718.8286533,
43 "projects_read": ["61e4bbab-9659-4abc-a01d-ba3a307becf9"],
45 "operationState": "PROCESSING",
46 "nsInstanceId": "45f588bd-5bf4-4181-b13b-f16a55a23be4",
47 "lcmOperationType": "instantiate",
48 "isCancelPending": False,
49 "id": "a571b1de-19e5-48bd-b252-ba0ad7d540c9",
50 "_id": "a571b1de-19e5-48bd-b252-ba0ad7d540c9",
51 "isAutomaticInvocation": False,
53 "nsInstance": "/osm/nslcm/v1/ns_instances/45f588bd-5bf4-4181-b13b-f16a55a23be4",
54 "self": "/osm/nslcm/v1/ns_lcm_op_occs/a571b1de-19e5-48bd-b252-ba0ad7d540c9",
57 "vimAccountId": "eb553051-5b6c-4ad6-939b-2ad23bd82e57",
58 "lcmOperationType": "instantiate",
59 "nsDescription": "just a test",
60 "nsdId": "0f4e658f-62a6-4f73-8623-270e8f0a18bc",
61 "nsName": "ThreeNsd plain placement",
64 "eb553051-5b6c-4ad6-939b-2ad23bd82e57",
65 "576bbe0a-b95d-4ced-a63e-f387f8e6e2ce",
66 "3d1ffc5d-b36d-4f69-8356-7f59c740ca2f",
67 "db54dcd4-9fc4-441c-8820-17bce0aef2c3",
69 "nsr_id": "45f588bd-5bf4-4181-b13b-f16a55a23be4",
70 "placement-engine": "PLA",
71 "nsInstanceId": "45f588bd-5bf4-4181-b13b-f16a55a23be4",
75 nslcmop_record_w_pinning
= {
76 "statusEnteredTime": 1574627411.420499,
77 "startTime": 1574627411.420499,
79 "created": 1574627411.4209971,
80 "projects_write": ["61e4bbab-9659-4abc-a01d-ba3a307becf9"],
81 "worker": "e5121e773e8b",
82 "modified": 1574627411.4209971,
83 "projects_read": ["61e4bbab-9659-4abc-a01d-ba3a307becf9"],
85 "operationState": "PROCESSING",
86 "nsInstanceId": "61587478-ea25-44eb-9f13-7005046ddb08",
87 "lcmOperationType": "instantiate",
88 "isCancelPending": False,
89 "id": "80f95a17-6fa7-408d-930f-40aa4589d074",
90 "_id": "80f95a17-6fa7-408d-930f-40aa4589d074",
91 "isAutomaticInvocation": False,
93 "nsInstance": "/osm/nslcm/v1/ns_instances/61587478-ea25-44eb-9f13-7005046ddb08",
94 "self": "/osm/nslcm/v1/ns_lcm_op_occs/80f95a17-6fa7-408d-930f-40aa4589d074",
97 "vimAccountId": "576bbe0a-b95d-4ced-a63e-f387f8e6e2ce",
98 "nsr_id": "61587478-ea25-44eb-9f13-7005046ddb08",
99 "nsDescription": "default description",
100 "nsdId": "0f4e658f-62a6-4f73-8623-270e8f0a18bc",
101 "validVimAccounts": [
102 "eb553051-5b6c-4ad6-939b-2ad23bd82e57",
103 "576bbe0a-b95d-4ced-a63e-f387f8e6e2ce",
104 "3d1ffc5d-b36d-4f69-8356-7f59c740ca2f",
105 "db54dcd4-9fc4-441c-8820-17bce0aef2c3",
107 "nsName": "ThreeVnfTest2",
108 "wimAccountId": False,
111 "vimAccountId": "3d1ffc5d-b36d-4f69-8356-7f59c740ca2f",
112 "member-vnf-index": "1",
115 "placementEngine": "PLA",
116 "nsInstanceId": "61587478-ea25-44eb-9f13-7005046ddb08",
117 "lcmOperationType": "instantiate",
121 nslcmop_record_w_pinning_and_order_constraints
= {
123 "nsInstance": "/osm/nslcm/v1/ns_instances/7c4c3d94-ebb2-44e8-b236-d876b118434e",
124 "self": "/osm/nslcm/v1/ns_lcm_op_occs/fd7c9e15-38aa-4fc5-913c-417b26859fb0",
126 "id": "fd7c9e15-38aa-4fc5-913c-417b26859fb0",
127 "operationState": "PROCESSING",
128 "isAutomaticInvocation": False,
129 "nsInstanceId": "7c4c3d94-ebb2-44e8-b236-d876b118434e",
130 "_id": "fd7c9e15-38aa-4fc5-913c-417b26859fb0",
131 "isCancelPending": False,
132 "startTime": 1574772631.6932728,
133 "statusEnteredTime": 1574772631.6932728,
134 "lcmOperationType": "instantiate",
136 "placementEngine": "PLA",
137 "placement-constraints": {
140 "id": "three_vnf_constrained_vld_1",
141 "link-constraints": {"latency": 120, "jitter": 20},
144 "link_constraints": {"latency": 120, "jitter": 20},
145 "id": "three_vnf_constrained_nsd_vld_2",
149 "nsName": "ThreeVnfTest2",
150 "nsDescription": "default description",
151 "nsr_id": "7c4c3d94-ebb2-44e8-b236-d876b118434e",
152 "nsdId": "0f4e658f-62a6-4f73-8623-270e8f0a18bc",
153 "validVimAccounts": [
154 "eb553051-5b6c-4ad6-939b-2ad23bd82e57",
155 "576bbe0a-b95d-4ced-a63e-f387f8e6e2ce",
156 "3d1ffc5d-b36d-4f69-8356-7f59c740ca2f",
157 "db54dcd4-9fc4-441c-8820-17bce0aef2c3",
159 "wimAccountId": False,
162 "member-vnf-index": "3",
163 "vimAccountId": "3d1ffc5d-b36d-4f69-8356-7f59c740ca2f",
166 "nsInstanceId": "7c4c3d94-ebb2-44e8-b236-d876b118434e",
167 "lcmOperationType": "instantiate",
168 "vimAccountId": "576bbe0a-b95d-4ced-a63e-f387f8e6e2ce",
171 "projects_read": ["61e4bbab-9659-4abc-a01d-ba3a307becf9"],
172 "modified": 1574772631.693885,
173 "projects_write": ["61e4bbab-9659-4abc-a01d-ba3a307becf9"],
174 "created": 1574772631.693885,
175 "worker": "e5121e773e8b",
181 "_id": "73cd1a1b-333e-4e29-8db2-00d23bd9b644",
183 "name": "OpenStack1",
184 "vim_url": "http://10.234.12.47:5000/v3",
185 "vim_type": "openstack",
186 "vim_tenant_name": "osm_demo",
187 "vim_password": "O/mHomfXPmCrTvUbYXVoyg==",
188 "schema_version": "1.1",
190 "modified": 1565597984.3155663,
192 "RO": "f0c1b516-bcd9-11e9-bb73-02420aff0030",
193 "RO-account": "f0d45496-bcd9-11e9-bb73-02420aff0030",
195 "projects_write": ["admin"],
196 "operationalState": "ENABLED",
197 "detailed-status": "Done",
198 "created": 1565597984.3155663,
199 "projects_read": ["admin"],
204 "_id": "684165ea-2cf9-4fbd-ac22-8464ca07d1d8",
206 "name": "OpenStack2",
207 "vim_url": "http://10.234.12.44:5000/v3",
208 "vim_tenant_name": "osm_demo",
209 "vim_password": "Rw7gln9liP4ClMyHd5OFsw==",
210 "description": "Openstack on NUC",
211 "vim_type": "openstack",
213 "modified": 1566474766.7288046,
215 "RO": "5bc59656-c4d3-11e9-b1e5-02420aff0006",
216 "RO-account": "5bd772e0-c4d3-11e9-b1e5-02420aff0006",
218 "projects_write": ["admin"],
219 "operationalState": "ENABLED",
220 "detailed-status": "Done",
221 "created": 1566474766.7288046,
222 "projects_read": ["admin"],
225 "schema_version": "1.1",
228 "_id": "8460b670-31cf-4fae-9f3e-d0dd6c57b61e",
230 "name": "OpenStack1",
231 "vim_url": "http://10.234.12.47:5000/v3",
232 "vim_type": "openstack",
233 "vim_tenant_name": "osm_demo",
234 "vim_password": "NsgJJDlCdKreX30FQFNz7A==",
235 "description": "Openstack on Dell",
237 "modified": 1566992449.5942867,
239 "RO": "aed94f86-c988-11e9-bb38-02420aff0088",
240 "RO-account": "aee72fac-c988-11e9-bb38-02420aff0088",
242 "projects_write": ["0a5d0c5b-7e08-48a1-a686-642a038bbd70"],
243 "operationalState": "ENABLED",
244 "detailed-status": "Done",
245 "created": 1566992449.5942867,
246 "projects_read": ["0a5d0c5b-7e08-48a1-a686-642a038bbd70"],
249 "schema_version": "1.1",
252 "_id": "9b8b5268-acb7-4893-b494-a77656b418f2",
254 "name": "OpenStack2",
255 "vim_url": "http://10.234.12.44:5000/v3",
256 "vim_type": "openstack",
257 "vim_tenant_name": "osm_demo",
258 "vim_password": "AnAV3xtoiwwdnAfv0KahSw==",
259 "description": "Openstack on NUC",
261 "modified": 1566992484.9190753,
263 "RO": "c3d61158-c988-11e9-bb38-02420aff0088",
264 "RO-account": "c3ec973e-c988-11e9-bb38-02420aff0088",
266 "projects_write": ["0a5d0c5b-7e08-48a1-a686-642a038bbd70"],
267 "operationalState": "ENABLED",
268 "detailed-status": "Done",
269 "created": 1566992484.9190753,
270 "projects_read": ["0a5d0c5b-7e08-48a1-a686-642a038bbd70"],
273 "schema_version": "1.1",
276 "_id": "3645f215-f32d-4355-b5ab-df0a2e2233c3",
278 "name": "OpenStack3",
279 "vim_url": "http://10.234.12.46:5000/v3",
280 "vim_tenant_name": "osm_demo",
281 "vim_password": "XkG2w8e8/DiuohCFNp0+lQ==",
282 "description": "Openstack on NUC",
283 "vim_type": "openstack",
285 "modified": 1567421247.7016313,
287 "RO": "0e80f6a2-cd6f-11e9-bb50-02420aff00b6",
288 "RO-account": "0e974524-cd6f-11e9-bb50-02420aff00b6",
290 "projects_write": ["0a5d0c5b-7e08-48a1-a686-642a038bbd70"],
291 "operationalState": "ENABLED",
292 "detailed-status": "Done",
293 "created": 1567421247.7016313,
294 "projects_read": ["0a5d0c5b-7e08-48a1-a686-642a038bbd70"],
296 "schema_version": "1.1",
300 "_id": "53f8f2bb-88b5-4bf9-babf-556698b5261f",
302 "name": "OpenStack4",
303 "vim_url": "http://10.234.12.43:5000/v3",
304 "vim_tenant_name": "osm_demo",
305 "vim_password": "GLrgVn8fMVneXMZq1r4yVA==",
306 "description": "Openstack on NUC",
307 "vim_type": "openstack",
309 "modified": 1567421296.1576457,
311 "RO": "2b43c756-cd6f-11e9-bb50-02420aff00b6",
312 "RO-account": "2b535aea-cd6f-11e9-bb50-02420aff00b6",
314 "projects_write": ["0a5d0c5b-7e08-48a1-a686-642a038bbd70"],
315 "operationalState": "ENABLED",
316 "detailed-status": "Done",
317 "created": 1567421296.1576457,
318 "projects_read": ["0a5d0c5b-7e08-48a1-a686-642a038bbd70"],
320 "schema_version": "1.1",
325 # FIXME this is not correct re mgmt-network setting.
327 "_id": "15fc1941-f095-4cd8-af2d-1000bd6d9eaa",
329 "modified": 1567672251.7531693,
331 "pkg-dir": "ns_constrained_nsd",
333 "descriptor": "ns_constrained_nsd/ns_constrained_nsd.yaml",
334 "zipfile": "package.tar.gz",
335 "folder": "15fc1941-f095-4cd8-af2d-1000bd6d9eaa",
336 "path": "/app/storage/",
338 "onboardingState": "ONBOARDED",
339 "usageState": "NOT_IN_USE",
340 "projects_write": ["0a5d0c5b-7e08-48a1-a686-642a038bbd70"],
341 "operationalState": "ENABLED",
342 "userDefinedData": {},
343 "created": 1567672251.7531693,
344 "projects_read": ["0a5d0c5b-7e08-48a1-a686-642a038bbd70"],
346 "id": "three_vnf_constrained_nsd_low",
347 "name": "three_vnf_constrained_nsd_low",
348 "description": "Placement constraints NSD",
349 "designer": "ArctosLabs",
351 "vnfd-id": ["cirros_vnfd_v2"],
358 "vnfd-id": "cirros_vnfd_v2",
359 "virtual-link-connectivity": [
361 "virtual-link-profile-id": "three_vnf_constrained_nsd_low_vld1",
362 "constituent-cpd-id": [
364 "constituent-base-element-id": "one",
365 "constituent-cpd-id": "vnf-cp0-ext",
373 "vnfd-id": "cirros_vnfd_v2",
374 "virtual-link-connectivity": [
376 "virtual-link-profile-id": "three_vnf_constrained_nsd_low_vld1",
377 "constituent-cpd-id": [
379 "constituent-base-element-id": "two",
380 "constituent-cpd-id": "vnf-cp0-ext",
385 "virtual-link-profile-id": "three_vnf_constrained_nsd_low_vld2",
386 "constituent-cpd-id": [
388 "constituent-base-element-id": "two",
389 "constituent-cpd-id": "vnf-cp0-ext",
397 "vnfd-id": "cirros_vnfd_v2",
398 "virtual-link-connectivity": [
400 "virtual-link-profile-id": "three_vnf_constrained_nsd_low_vld2",
401 "constituent-cpd-id": [
403 "constituent-base-element-id": "three",
404 "constituent-cpd-id": "vnf-cp0-ext",
413 "virtual-link-desc": [
415 "id": "three_vnf_constrained_nsd_low_vld1",
416 "mgmt-network": True,
417 "vim-network-name": "external",
420 "id": "three_vnf_constrained_nsd_low_vld2",
421 "mgmt-network": True,
422 "vim-network-name": "lanretxe",
428 ######################################################
429 # These are helper functions to handle unittest of asyncio.
430 # Inspired by: https://blog.miguelgrinberg.com/post/unit-testing-asyncio-code
431 def _run(co_routine
):
432 return asyncio
.get_event_loop().run_until_complete(co_routine
)
435 def _async_mock(*args
, **kwargs
):
436 m
= mock
.MagicMock(*args
, **kwargs
)
438 async def mock_coro(*args
, **kwargs
):
439 return m(*args
, **kwargs
)
445 ######################################################
448 class TestServer(TestCase
):
449 def _produce_ut_vim_accounts_info(self
, list_of_vims
):
451 FIXME temporary, we will need more control over vim_urls and _id for test purpose - make a generator
452 :return: vim_url and _id as dict, i.e. extract these from vim_accounts data
454 return {_
["name"]: _
["_id"] for _
in list_of_vims
}
456 def _produce_ut_vnf_price_list(self
):
457 price_list_file
= "vnf_price_list.yaml"
458 with
open(str(Path(price_list_file
))) as pl_fd
:
459 price_list_data
= yaml
.safe_load_all(pl_fd
)
461 i
["vnfd"]: {i1
["vim_name"]: i1
["price"] for i1
in i
["prices"]}
462 for i
in next(price_list_data
)
465 def _populate_pil_info(self
, file):
467 FIXME we need more control over content in pil information - more files or generator and data
468 Note str(Path()) is a 3.5 thing
470 with
open(str(Path(file))) as pp_fd
:
471 test_data
= yaml
.safe_load_all(pp_fd
)
472 return next(test_data
)
474 @mock.patch
.object(Config
, "_read_config_file")
478 side_effect
=["doesnotmatter", "memory", "memory", "local", "doesnotmatter"],
480 def serverSetup(self
, mock_get
, mock__read_config_file
):
482 Helper that returns a Server object
488 def _adjust_path(self
, file):
489 """In case we are not running from test directory,
490 then assume we are in top level directory (e.g. running from tox) and adjust file path accordingly
492 path_component
= "/osm_pla/test/"
493 real_path
= os
.path
.realpath(file)
494 if path_component
not in real_path
:
496 os
.path
.dirname(real_path
)
498 + os
.path
.basename(real_path
)
503 def test__get_nslcmop(self
):
504 server
= self
.serverSetup()
506 _
= server
._get
_nslcmop
(nslcmop_record_wo_pinning
["id"])
507 server
.db
.get_one
.assert_called_with(
508 "nslcmops", {"_id": nslcmop_record_wo_pinning
["id"]}
511 def test__get_nsd(self
): # OK
512 server
= self
.serverSetup()
514 _
= server
._get
_nsd
(nslcmop_record_wo_pinning
["operationParams"]["nsdId"])
515 server
.db
.get_one
.assert_called_with(
516 "nsds", {"_id": nslcmop_record_wo_pinning
["operationParams"]["nsdId"]}
519 def test__create_vnf_id_maps(self
):
520 server
= self
.serverSetup()
522 expected_mvi2mzn
= {"one": "VNF0", "two": "VNF1", "three": "VNF2"}
523 expected_mzn2mvi
= {"VNF0": "one", "VNF1": "two", "VNF2": "three"}
525 nsd_for_test
= copy
.deepcopy(nsd_from_db
)
526 mvi2mzn
, mzn2mvi
= server
._create
_vnf
_id
_maps
(nsd_for_test
)
528 self
.assertDictEqual(
529 expected_mvi2mzn
, mvi2mzn
, "Faulty mzn2member-vnf-index mapping"
531 self
.assertDictEqual(
532 expected_mzn2mvi
, mzn2mvi
, "Faulty mzn2member-vnf-index mapping"
535 def test__get_vim_accounts(self
): # OK
536 server
= self
.serverSetup()
538 _
= server
._get
_vim
_accounts
(
539 nslcmop_record_wo_pinning
["operationParams"]["validVimAccounts"]
541 server
.db
.get_list
.assert_called_with(
543 {"_id": nslcmop_record_wo_pinning
["operationParams"]["validVimAccounts"]},
546 def test__get_vnf_price_list(self
):
547 server
= self
.serverSetup()
548 pl1
= server
._get
_vnf
_price
_list
(
549 Path(self
._adjust
_path
("./vnf_price_list.yaml"))
551 self
.assertIs(type(pl1
), dict, "price list not a dictionary")
552 for k
, v
in pl1
.items():
553 self
.assertIs(type(v
), dict, "price list values not a dict")
555 pl2
= server
._get
_vnf
_price
_list
(
556 Path(self
._adjust
_path
("./vnf_price_list_keys.yaml")), "hackfest_project_a"
558 self
.assertIs(type(pl2
), dict, "price list not a dictionary")
559 for k
, v
in pl2
.items():
560 self
.assertIs(type(v
), dict, "price list values not a dict")
561 self
.assertEqual(pl1
, pl2
, "non-project and project price lists differ")
563 def test__get_pil_info(self
):
564 server
= self
.serverSetup()
565 ppi
= server
._get
_pil
_info
(Path(self
._adjust
_path
("./pil_price_list.yaml")))
566 self
.assertIs(type(ppi
), dict, "pil is not a dict")
567 self
.assertIn("pil", ppi
.keys(), "pil has no pil key")
568 self
.assertIs(type(ppi
["pil"]), list, "pil does not contain a list")
569 # check for expected keys
577 self
.assertEqual(expected_keys
, ppi
["pil"][0].keys(), "expected keys not found")
579 # def test_handle_kafka_command(self): # OK
580 # server = self.serverSetup()
581 # server.loop.create_task = Mock()
582 # server.handle_kafka_command("pli", "get_placement", {})
583 # server.loop.create_task.assert_not_called()
584 # server.loop.create_task.reset_mock()
585 # server.handle_kafka_command(
586 # "pla", "get_placement", {"nslcmopId": nslcmop_record_wo_pinning["id"]}
588 # self.assertTrue(server.loop.create_task.called, "create_task not called")
589 # args, kwargs = server.loop.create_task.call_args
590 # self.assertIn("Server.get_placement", str(args[0]), "get_placement not called")
593 NsPlacementDataFactory
, "__init__", lambda x0
, x1
, x2
, x3
, x4
, x5
, x6
: None
595 @mock.patch
.object(MznPlacementConductor
, "do_placement_computation")
596 @mock.patch
.object(NsPlacementDataFactory
, "create_ns_placement_data")
597 @mock.patch
.object(Server
, "_get_vim_accounts")
598 @mock.patch
.object(Server
, "_get_nsd")
599 @mock.patch
.object(Server
, "_get_nslcmop")
600 @mock.patch
.object(Server
, "_get_vnf_price_list")
601 @mock.patch
.object(Server
, "_get_pil_info")
602 @mock.patch
.object(Server
, "_get_projects")
603 def test_get_placement(
607 mock_get_vnf_price_list
,
610 mock__get_vim_accounts
,
611 mock_create_ns_placement_data
,
612 mock_do_placement_computation
,
615 run _get_placement and check that things get called as expected
618 placement_ret_val
= [
620 "vimAccountId": "bbbbbbbb-38f5-438d-b8ee-3f93b3531f87",
621 "member-vnf-index": "VNF0",
624 "vimAccountId": "aaaaaaaa-38f5-438d-b8ee-3f93b3531f87",
625 "member-vnf-index": "VNF1",
628 "vimAccountId": "aaaaaaaa-38f5-438d-b8ee-3f93b3531f87",
629 "member-vnf-index": "VNF2",
632 server
= self
.serverSetup()
634 server
.msgBus
.aiowrite
= _async_mock()
635 nsd_for_test
= copy
.deepcopy(nsd_from_db
)
636 mock__get_nsd
.return_value
= nsd_for_test
637 mock__get_vim_accounts
.return_value
= list_of_vims
639 # FIXME need update to match nslcmop, not for test but for consistency
640 mock_do_placement_computation
.return_value
= placement_ret_val
641 _run(server
.get_placement(nslcmop_record_wo_pinning
["id"]))
644 mock_get_projects
.called
, "_get_projects not called as expected"
647 mock_get_vnf_price_list
.called
, "_get_vnf_price_list not called as expected"
650 mock_get_pil_info
.called
, "_get_pil_info not called as expected"
652 self
.assertTrue(mock__get_nslcmop
.called
, "_get_nslcmop not called as expected")
653 # mock_get_nsd.assert_called_once() assert_called_once() for python > 3.5
654 self
.assertTrue(mock__get_nsd
.called
, "get_nsd not called as expected")
655 # mock_get_enabled_vims.assert_called_once() assert_called_once() for python > 3.5
657 mock__get_vim_accounts
.called
, "get_vim_accounts not called as expected"
659 # mock_create_ns_placement_data.assert_called_once() assert_called_once() for python > 3.5
661 mock_create_ns_placement_data
.called
,
662 "create_ns_placement_data not called as expected",
664 # mock_do_placement_computation.assert_called_once() assert_called_once() for python > 3.5
666 mock_do_placement_computation
.called
,
667 "do_placement_computation not called as expected",
669 self
.assertTrue(server
.msgBus
.aiowrite
.mock
.called
)
671 args
, kwargs
= server
.msgBus
.aiowrite
.mock
.call_args
672 self
.assertTrue(len(args
) == 3, "invalid format")
673 self
.assertEqual("pla", args
[0], "topic invalid")
674 self
.assertEqual("placement", args
[1], "message invalid")
675 # extract placement result and check content
676 rsp_payload
= args
[2]
678 expected_rsp_keys
= {"placement"}
681 set(rsp_payload
.keys()),
682 "placement response missing keys",
684 self
.assertIs(type(rsp_payload
["placement"]), dict, "placement not a dict")
686 expected_placement_keys
= {"vnf", "nslcmopId"}
688 expected_placement_keys
,
689 set(rsp_payload
["placement"]),
690 "placement keys invalid",
693 vim_account_candidates
= [e
["vimAccountId"] for e
in placement_ret_val
]
696 nslcmop_record_wo_pinning
["id"],
697 rsp_payload
["placement"]["nslcmopId"],
701 self
.assertIs(type(rsp_payload
["placement"]["vnf"]), list, "vnf not a list")
702 expected_vnf_keys
= {"vimAccountId", "member-vnf-index"}
705 set(rsp_payload
["placement"]["vnf"][0]),
706 "placement['vnf'] missing keys",
709 rsp_payload
["placement"]["vnf"][0]["vimAccountId"],
710 vim_account_candidates
,
711 "vimAccountId invalid",
715 NsPlacementDataFactory
, "__init__", lambda x0
, x1
, x2
, x3
, x4
, x5
, x6
: None
717 @mock.patch
.object(MznPlacementConductor
, "do_placement_computation")
718 @mock.patch
.object(NsPlacementDataFactory
, "create_ns_placement_data")
719 @mock.patch
.object(Server
, "_get_vim_accounts")
720 @mock.patch
.object(Server
, "_get_nsd")
721 @mock.patch
.object(Server
, "_get_nslcmop")
722 @mock.patch
.object(Server
, "_get_vnf_price_list")
723 @mock.patch
.object(Server
, "_get_pil_info")
724 @mock.patch
.object(Server
, "_get_projects")
725 def test_get_placement_with_pinning(
729 mock_get_vnf_price_list
,
732 mock__get_vim_accounts
,
733 mock_create_ns_placement_data
,
734 mock_do_placement_computation
,
737 run _get_placement and check that things get called as expected
740 placement_ret_val
= [
742 "vimAccountId": "bbbbbbbb-38f5-438d-b8ee-3f93b3531f87",
743 "member-vnf-index": "VNF0",
746 "vimAccountId": "aaaaaaaa-38f5-438d-b8ee-3f93b3531f87",
747 "member-vnf-index": "VNF1",
750 "vimAccountId": "aaaaaaaa-38f5-438d-b8ee-3f93b3531f87",
751 "member-vnf-index": "VNF2",
754 server
= self
.serverSetup()
756 server
.msgBus
.aiowrite
= _async_mock()
757 nsd_for_test
= copy
.deepcopy(nsd_from_db
)
758 mock__get_nsd
.return_value
= nsd_for_test
759 mock__get_vim_accounts
.return_value
= list_of_vims
761 # FIXME need update to match nslcmop, not for test but for consistency
762 mock_do_placement_computation
.return_value
= placement_ret_val
763 _run(server
.get_placement(nslcmop_record_w_pinning
["id"]))
766 (mock_get_projects
.called
, "_get_projects not called as expected")
769 mock_get_vnf_price_list
.called
, "_get_vnf_price_list not called as expected"
772 mock_get_pil_info
.called
, "_get_pil_info not called as expected"
774 self
.assertTrue(mock__get_nslcmop
.called
, "_get_nslcmop not called as expected")
775 # mock_get_nsd.assert_called_once() assert_called_once() for python > 3.5
776 self
.assertTrue(mock__get_nsd
.called
, "get_nsd not called as expected")
777 # mock_get_enabled_vims.assert_called_once() assert_called_once() for python > 3.5
779 mock__get_vim_accounts
.called
, "get_vim_accounts not called as expected"
781 # mock_create_ns_placement_data.assert_called_once() assert_called_once() for python > 3.5
783 mock_create_ns_placement_data
.called
,
784 "create_ns_placement_data not called as expected",
786 # mock_do_placement_computation.assert_called_once() assert_called_once() for python > 3.5
788 mock_do_placement_computation
.called
,
789 "do_placement_computation not called as expected",
791 self
.assertTrue(server
.msgBus
.aiowrite
.mock
.called
)
793 args
, kwargs
= server
.msgBus
.aiowrite
.mock
.call_args
794 self
.assertTrue(len(args
) == 3, "invalid format")
795 self
.assertEqual("pla", args
[0], "topic invalid")
796 self
.assertEqual("placement", args
[1], "message invalid")
797 # extract placement result and check content
798 rsp_payload
= args
[2]
800 expected_rsp_keys
= {"placement"}
803 set(rsp_payload
.keys()),
804 "placement response missing keys",
806 self
.assertIs(type(rsp_payload
["placement"]), dict, "placement not a dict")
808 expected_placement_keys
= {"vnf", "nslcmopId"}
810 expected_placement_keys
,
811 set(rsp_payload
["placement"]),
812 "placement keys invalid",
815 vim_account_candidates
= [e
["vimAccountId"] for e
in placement_ret_val
]
818 nslcmop_record_w_pinning
["id"],
819 rsp_payload
["placement"]["nslcmopId"],
823 self
.assertIs(type(rsp_payload
["placement"]["vnf"]), list, "vnf not a list")
824 expected_vnf_keys
= {"vimAccountId", "member-vnf-index"}
827 set(rsp_payload
["placement"]["vnf"][0]),
828 "placement['vnf'] missing keys",
831 rsp_payload
["placement"]["vnf"][0]["vimAccountId"],
832 vim_account_candidates
,
833 "vimAccountId invalid",
836 # Note: does not mock reading of price list and pil_info
838 NsPlacementDataFactory
, "__init__", lambda x0
, x1
, x2
, x3
, x4
, x5
: None
840 @mock.patch
.object(MznPlacementConductor
, "do_placement_computation")
841 @mock.patch
.object(NsPlacementDataFactory
, "create_ns_placement_data")
842 @mock.patch
.object(Server
, "_get_vim_accounts")
843 @mock.patch
.object(Server
, "_get_nsd")
844 @mock.patch
.object(Server
, "_get_nslcmop")
845 def test_get_placement_w_exception(
849 mock__get_vim_accounts
,
850 mock_create_ns_placement_data
,
851 mock_do_placement_computation
,
854 check that raised exceptions are handled and response provided accordingly
856 server
= self
.serverSetup()
858 server
.msgBus
.aiowrite
= _async_mock()
859 nsd_for_test
= copy
.deepcopy(nsd_from_db
)
860 mock__get_nsd
.return_value
= nsd_for_test
861 mock__get_nsd
.side_effect
= RuntimeError("kaboom!")
862 mock__get_vim_accounts
.return_value
= list_of_vims
863 mock_do_placement_computation
.return_value
= [
865 "vimAccountId": "bbbbbbbb-38f5-438d-b8ee-3f93b3531f87",
866 "member-vnf-index": "1",
869 "vimAccountId": "aaaaaaaa-38f5-438d-b8ee-3f93b3531f87",
870 "member-vnf-index": "2",
873 "vimAccountId": "aaaaaaaa-38f5-438d-b8ee-3f93b3531f87",
874 "member-vnf-index": "3",
878 _run(server
.get_placement(nslcmop_record_w_pinning
["id"]))
879 self
.assertTrue(server
.msgBus
.aiowrite
.mock
.called
)
880 args
, kwargs
= server
.msgBus
.aiowrite
.mock
.call_args
881 rsp_payload
= args
[2]
882 expected_keys
= {"placement"}
884 expected_keys
, set(rsp_payload
.keys()), "placement response missing keys"
886 self
.assertIs(type(rsp_payload
["placement"]["vnf"]), list, "vnf not a list")
887 self
.assertEqual([], rsp_payload
["placement"]["vnf"], "vnf list not empty")
889 nslcmop_record_w_pinning
["id"],
890 rsp_payload
["placement"]["nslcmopId"],