1 |
|
# Copyright 2020 ArctosLabs Scandinavia AB |
2 |
|
# |
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 |
6 |
|
# |
7 |
|
# http://www.apache.org/licenses/LICENSE-2.0 |
8 |
|
# |
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 |
12 |
|
# implied. |
13 |
|
# See the License for the specific language governing permissions and |
14 |
|
# limitations under the License. |
15 |
|
|
16 |
|
# pylint: disable=E1120 |
17 |
|
|
18 |
1 |
import asyncio |
19 |
1 |
import copy |
20 |
1 |
import os |
21 |
1 |
import sys |
22 |
1 |
from unittest import TestCase, mock |
23 |
1 |
from unittest.mock import Mock |
24 |
|
|
25 |
1 |
import yaml |
26 |
|
|
27 |
1 |
from osm_pla.placement.mznplacement import NsPlacementDataFactory, MznPlacementConductor |
28 |
1 |
from pathlib import Path |
29 |
|
|
30 |
|
# need to Mock the imports from osm_common made in Server and Config beforehand |
31 |
1 |
sys.modules["osm_common"] = Mock() |
32 |
1 |
from osm_pla.server.server import Server # noqa: E402 |
33 |
1 |
from osm_pla.config.config import Config # noqa: E402 |
34 |
|
|
35 |
1 |
nslcmop_record_wo_pinning = { |
36 |
|
"statusEnteredTime": 1574625718.8280587, |
37 |
|
"startTime": 1574625718.8280587, |
38 |
|
"_admin": { |
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"], |
44 |
|
}, |
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, |
52 |
|
"links": { |
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", |
55 |
|
}, |
56 |
|
"operationParams": { |
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", |
62 |
|
"ssh_keys": [], |
63 |
|
"validVimAccounts": [ |
64 |
|
"eb553051-5b6c-4ad6-939b-2ad23bd82e57", |
65 |
|
"576bbe0a-b95d-4ced-a63e-f387f8e6e2ce", |
66 |
|
"3d1ffc5d-b36d-4f69-8356-7f59c740ca2f", |
67 |
|
"db54dcd4-9fc4-441c-8820-17bce0aef2c3", |
68 |
|
], |
69 |
|
"nsr_id": "45f588bd-5bf4-4181-b13b-f16a55a23be4", |
70 |
|
"placement-engine": "PLA", |
71 |
|
"nsInstanceId": "45f588bd-5bf4-4181-b13b-f16a55a23be4", |
72 |
|
}, |
73 |
|
} |
74 |
|
|
75 |
1 |
nslcmop_record_w_pinning = { |
76 |
|
"statusEnteredTime": 1574627411.420499, |
77 |
|
"startTime": 1574627411.420499, |
78 |
|
"_admin": { |
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"], |
84 |
|
}, |
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, |
92 |
|
"links": { |
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", |
95 |
|
}, |
96 |
|
"operationParams": { |
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", |
106 |
|
], |
107 |
|
"nsName": "ThreeVnfTest2", |
108 |
|
"wimAccountId": False, |
109 |
|
"vnf": [ |
110 |
|
{ |
111 |
|
"vimAccountId": "3d1ffc5d-b36d-4f69-8356-7f59c740ca2f", |
112 |
|
"member-vnf-index": "1", |
113 |
|
} |
114 |
|
], |
115 |
|
"placementEngine": "PLA", |
116 |
|
"nsInstanceId": "61587478-ea25-44eb-9f13-7005046ddb08", |
117 |
|
"lcmOperationType": "instantiate", |
118 |
|
}, |
119 |
|
} |
120 |
|
|
121 |
1 |
nslcmop_record_w_pinning_and_order_constraints = { |
122 |
|
"links": { |
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", |
125 |
|
}, |
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", |
135 |
|
"operationParams": { |
136 |
|
"placementEngine": "PLA", |
137 |
|
"placement-constraints": { |
138 |
|
"vld-constraints": [ |
139 |
|
{ |
140 |
|
"id": "three_vnf_constrained_vld_1", |
141 |
|
"link-constraints": {"latency": 120, "jitter": 20}, |
142 |
|
}, |
143 |
|
{ |
144 |
|
"link_constraints": {"latency": 120, "jitter": 20}, |
145 |
|
"id": "three_vnf_constrained_nsd_vld_2", |
146 |
|
}, |
147 |
|
] |
148 |
|
}, |
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", |
158 |
|
], |
159 |
|
"wimAccountId": False, |
160 |
|
"vnf": [ |
161 |
|
{ |
162 |
|
"member-vnf-index": "3", |
163 |
|
"vimAccountId": "3d1ffc5d-b36d-4f69-8356-7f59c740ca2f", |
164 |
|
} |
165 |
|
], |
166 |
|
"nsInstanceId": "7c4c3d94-ebb2-44e8-b236-d876b118434e", |
167 |
|
"lcmOperationType": "instantiate", |
168 |
|
"vimAccountId": "576bbe0a-b95d-4ced-a63e-f387f8e6e2ce", |
169 |
|
}, |
170 |
|
"_admin": { |
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", |
176 |
|
}, |
177 |
|
} |
178 |
|
|
179 |
1 |
list_of_vims = [ |
180 |
|
{ |
181 |
|
"_id": "73cd1a1b-333e-4e29-8db2-00d23bd9b644", |
182 |
|
"vim_user": "admin", |
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", |
189 |
|
"_admin": { |
190 |
|
"modified": 1565597984.3155663, |
191 |
|
"deployed": { |
192 |
|
"RO": "f0c1b516-bcd9-11e9-bb73-02420aff0030", |
193 |
|
"RO-account": "f0d45496-bcd9-11e9-bb73-02420aff0030", |
194 |
|
}, |
195 |
|
"projects_write": ["admin"], |
196 |
|
"operationalState": "ENABLED", |
197 |
|
"detailed-status": "Done", |
198 |
|
"created": 1565597984.3155663, |
199 |
|
"projects_read": ["admin"], |
200 |
|
}, |
201 |
|
"config": {}, |
202 |
|
}, |
203 |
|
{ |
204 |
|
"_id": "684165ea-2cf9-4fbd-ac22-8464ca07d1d8", |
205 |
|
"vim_user": "admin", |
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", |
212 |
|
"admin": { |
213 |
|
"modified": 1566474766.7288046, |
214 |
|
"deployed": { |
215 |
|
"RO": "5bc59656-c4d3-11e9-b1e5-02420aff0006", |
216 |
|
"RO-account": "5bd772e0-c4d3-11e9-b1e5-02420aff0006", |
217 |
|
}, |
218 |
|
"projects_write": ["admin"], |
219 |
|
"operationalState": "ENABLED", |
220 |
|
"detailed-status": "Done", |
221 |
|
"created": 1566474766.7288046, |
222 |
|
"projects_read": ["admin"], |
223 |
|
}, |
224 |
|
"config": {}, |
225 |
|
"schema_version": "1.1", |
226 |
|
}, |
227 |
|
{ |
228 |
|
"_id": "8460b670-31cf-4fae-9f3e-d0dd6c57b61e", |
229 |
|
"vim_user": "admin", |
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", |
236 |
|
"_admin": { |
237 |
|
"modified": 1566992449.5942867, |
238 |
|
"deployed": { |
239 |
|
"RO": "aed94f86-c988-11e9-bb38-02420aff0088", |
240 |
|
"RO-account": "aee72fac-c988-11e9-bb38-02420aff0088", |
241 |
|
}, |
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"], |
247 |
|
}, |
248 |
|
"config": {}, |
249 |
|
"schema_version": "1.1", |
250 |
|
}, |
251 |
|
{ |
252 |
|
"_id": "9b8b5268-acb7-4893-b494-a77656b418f2", |
253 |
|
"vim_user": "admin", |
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", |
260 |
|
"_admin": { |
261 |
|
"modified": 1566992484.9190753, |
262 |
|
"deployed": { |
263 |
|
"RO": "c3d61158-c988-11e9-bb38-02420aff0088", |
264 |
|
"RO-account": "c3ec973e-c988-11e9-bb38-02420aff0088", |
265 |
|
}, |
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"], |
271 |
|
}, |
272 |
|
"config": {}, |
273 |
|
"schema_version": "1.1", |
274 |
|
}, |
275 |
|
{ |
276 |
|
"_id": "3645f215-f32d-4355-b5ab-df0a2e2233c3", |
277 |
|
"vim_user": "admin", |
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", |
284 |
|
"_admin": { |
285 |
|
"modified": 1567421247.7016313, |
286 |
|
"deployed": { |
287 |
|
"RO": "0e80f6a2-cd6f-11e9-bb50-02420aff00b6", |
288 |
|
"RO-account": "0e974524-cd6f-11e9-bb50-02420aff00b6", |
289 |
|
}, |
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"], |
295 |
|
}, |
296 |
|
"schema_version": "1.1", |
297 |
|
"config": {}, |
298 |
|
}, |
299 |
|
{ |
300 |
|
"_id": "53f8f2bb-88b5-4bf9-babf-556698b5261f", |
301 |
|
"vim_user": "admin", |
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", |
308 |
|
"_admin": { |
309 |
|
"modified": 1567421296.1576457, |
310 |
|
"deployed": { |
311 |
|
"RO": "2b43c756-cd6f-11e9-bb50-02420aff00b6", |
312 |
|
"RO-account": "2b535aea-cd6f-11e9-bb50-02420aff00b6", |
313 |
|
}, |
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"], |
319 |
|
}, |
320 |
|
"schema_version": "1.1", |
321 |
|
"config": {}, |
322 |
|
}, |
323 |
|
] |
324 |
|
|
325 |
|
# FIXME this is not correct re mgmt-network setting. |
326 |
1 |
nsd_from_db = { |
327 |
|
"_id": "15fc1941-f095-4cd8-af2d-1000bd6d9eaa", |
328 |
|
"_admin": { |
329 |
|
"modified": 1567672251.7531693, |
330 |
|
"storage": { |
331 |
|
"pkg-dir": "ns_constrained_nsd", |
332 |
|
"fs": "local", |
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/", |
337 |
|
}, |
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"], |
345 |
|
}, |
346 |
|
"id": "three_vnf_constrained_nsd_low", |
347 |
|
"name": "three_vnf_constrained_nsd_low", |
348 |
|
"description": "Placement constraints NSD", |
349 |
|
"designer": "ArctosLabs", |
350 |
|
"version": "1.0", |
351 |
|
"vnfd-id": ["cirros_vnfd_v2"], |
352 |
|
"df": [ |
353 |
|
{ |
354 |
|
"id": "default-df", |
355 |
|
"vnf-profile": [ |
356 |
|
{ |
357 |
|
"id": "one", |
358 |
|
"vnfd-id": "cirros_vnfd_v2", |
359 |
|
"virtual-link-connectivity": [ |
360 |
|
{ |
361 |
|
"virtual-link-profile-id": "three_vnf_constrained_nsd_low_vld1", |
362 |
|
"constituent-cpd-id": [ |
363 |
|
{ |
364 |
|
"constituent-base-element-id": "one", |
365 |
|
"constituent-cpd-id": "vnf-cp0-ext", |
366 |
|
} |
367 |
|
], |
368 |
|
} |
369 |
|
], |
370 |
|
}, |
371 |
|
{ |
372 |
|
"id": "two", |
373 |
|
"vnfd-id": "cirros_vnfd_v2", |
374 |
|
"virtual-link-connectivity": [ |
375 |
|
{ |
376 |
|
"virtual-link-profile-id": "three_vnf_constrained_nsd_low_vld1", |
377 |
|
"constituent-cpd-id": [ |
378 |
|
{ |
379 |
|
"constituent-base-element-id": "two", |
380 |
|
"constituent-cpd-id": "vnf-cp0-ext", |
381 |
|
} |
382 |
|
], |
383 |
|
}, |
384 |
|
{ |
385 |
|
"virtual-link-profile-id": "three_vnf_constrained_nsd_low_vld2", |
386 |
|
"constituent-cpd-id": [ |
387 |
|
{ |
388 |
|
"constituent-base-element-id": "two", |
389 |
|
"constituent-cpd-id": "vnf-cp0-ext", |
390 |
|
} |
391 |
|
], |
392 |
|
}, |
393 |
|
], |
394 |
|
}, |
395 |
|
{ |
396 |
|
"id": "three", |
397 |
|
"vnfd-id": "cirros_vnfd_v2", |
398 |
|
"virtual-link-connectivity": [ |
399 |
|
{ |
400 |
|
"virtual-link-profile-id": "three_vnf_constrained_nsd_low_vld2", |
401 |
|
"constituent-cpd-id": [ |
402 |
|
{ |
403 |
|
"constituent-base-element-id": "three", |
404 |
|
"constituent-cpd-id": "vnf-cp0-ext", |
405 |
|
} |
406 |
|
], |
407 |
|
} |
408 |
|
], |
409 |
|
}, |
410 |
|
], |
411 |
|
} |
412 |
|
], |
413 |
|
"virtual-link-desc": [ |
414 |
|
{ |
415 |
|
"id": "three_vnf_constrained_nsd_low_vld1", |
416 |
|
"mgmt-network": True, |
417 |
|
"vim-network-name": "external", |
418 |
|
}, |
419 |
|
{ |
420 |
|
"id": "three_vnf_constrained_nsd_low_vld2", |
421 |
|
"mgmt-network": True, |
422 |
|
"vim-network-name": "lanretxe", |
423 |
|
}, |
424 |
|
], |
425 |
|
} |
426 |
|
|
427 |
|
|
428 |
|
###################################################### |
429 |
|
# These are helper functions to handle unittest of asyncio. |
430 |
|
# Inspired by: https://blog.miguelgrinberg.com/post/unit-testing-asyncio-code |
431 |
1 |
def _run(co_routine): |
432 |
1 |
return asyncio.get_event_loop().run_until_complete(co_routine) |
433 |
|
|
434 |
|
|
435 |
1 |
def _async_mock(*args, **kwargs): |
436 |
1 |
m = mock.MagicMock(*args, **kwargs) |
437 |
|
|
438 |
1 |
async def mock_coro(*args, **kwargs): |
439 |
1 |
return m(*args, **kwargs) |
440 |
|
|
441 |
1 |
mock_coro.mock = m |
442 |
1 |
return mock_coro |
443 |
|
|
444 |
|
|
445 |
|
###################################################### |
446 |
|
|
447 |
|
|
448 |
1 |
class TestServer(TestCase): |
449 |
1 |
def _produce_ut_vim_accounts_info(self, list_of_vims): |
450 |
|
""" |
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 |
453 |
|
""" |
454 |
0 |
return {_["name"]: _["_id"] for _ in list_of_vims} |
455 |
|
|
456 |
1 |
def _produce_ut_vnf_price_list(self): |
457 |
0 |
price_list_file = "vnf_price_list.yaml" |
458 |
0 |
with open(str(Path(price_list_file))) as pl_fd: |
459 |
0 |
price_list_data = yaml.safe_load_all(pl_fd) |
460 |
0 |
return { |
461 |
|
i["vnfd"]: {i1["vim_name"]: i1["price"] for i1 in i["prices"]} |
462 |
|
for i in next(price_list_data) |
463 |
|
} |
464 |
|
|
465 |
1 |
def _populate_pil_info(self, file): |
466 |
|
""" |
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 |
469 |
|
""" |
470 |
0 |
with open(str(Path(file))) as pp_fd: |
471 |
0 |
test_data = yaml.safe_load_all(pp_fd) |
472 |
0 |
return next(test_data) |
473 |
|
|
474 |
1 |
@mock.patch.object(Config, "_read_config_file") |
475 |
1 |
@mock.patch.object( |
476 |
|
Config, |
477 |
|
"get", |
478 |
|
side_effect=["doesnotmatter", "memory", "memory", "local", "doesnotmatter"], |
479 |
|
) |
480 |
1 |
def serverSetup(self, mock_get, mock__read_config_file): |
481 |
|
""" |
482 |
|
Helper that returns a Server object |
483 |
|
:return: |
484 |
|
""" |
485 |
1 |
cfg = Config(None) |
486 |
1 |
return Server(cfg) |
487 |
|
|
488 |
1 |
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 |
491 |
|
""" |
492 |
1 |
path_component = "/osm_pla/test/" |
493 |
1 |
real_path = os.path.realpath(file) |
494 |
1 |
if path_component not in real_path: |
495 |
1 |
return ( |
496 |
|
os.path.dirname(real_path) |
497 |
|
+ path_component |
498 |
|
+ os.path.basename(real_path) |
499 |
|
) |
500 |
|
else: |
501 |
0 |
return real_path |
502 |
|
|
503 |
1 |
def test__get_nslcmop(self): |
504 |
1 |
server = self.serverSetup() |
505 |
1 |
server.db = Mock() |
506 |
1 |
_ = server._get_nslcmop(nslcmop_record_wo_pinning["id"]) |
507 |
1 |
server.db.get_one.assert_called_with( |
508 |
|
"nslcmops", {"_id": nslcmop_record_wo_pinning["id"]} |
509 |
|
) |
510 |
|
|
511 |
1 |
def test__get_nsd(self): # OK |
512 |
1 |
server = self.serverSetup() |
513 |
1 |
server.db = Mock() |
514 |
1 |
_ = server._get_nsd(nslcmop_record_wo_pinning["operationParams"]["nsdId"]) |
515 |
1 |
server.db.get_one.assert_called_with( |
516 |
|
"nsds", {"_id": nslcmop_record_wo_pinning["operationParams"]["nsdId"]} |
517 |
|
) |
518 |
|
|
519 |
1 |
def test__create_vnf_id_maps(self): |
520 |
1 |
server = self.serverSetup() |
521 |
1 |
server.db = Mock() |
522 |
1 |
expected_mvi2mzn = {"one": "VNF0", "two": "VNF1", "three": "VNF2"} |
523 |
1 |
expected_mzn2mvi = {"VNF0": "one", "VNF1": "two", "VNF2": "three"} |
524 |
|
|
525 |
1 |
nsd_for_test = copy.deepcopy(nsd_from_db) |
526 |
1 |
mvi2mzn, mzn2mvi = server._create_vnf_id_maps(nsd_for_test) |
527 |
|
|
528 |
1 |
self.assertDictEqual( |
529 |
|
expected_mvi2mzn, mvi2mzn, "Faulty mzn2member-vnf-index mapping" |
530 |
|
) |
531 |
1 |
self.assertDictEqual( |
532 |
|
expected_mzn2mvi, mzn2mvi, "Faulty mzn2member-vnf-index mapping" |
533 |
|
) |
534 |
|
|
535 |
1 |
def test__get_vim_accounts(self): # OK |
536 |
1 |
server = self.serverSetup() |
537 |
1 |
server.db = Mock() |
538 |
1 |
_ = server._get_vim_accounts( |
539 |
|
nslcmop_record_wo_pinning["operationParams"]["validVimAccounts"] |
540 |
|
) |
541 |
1 |
server.db.get_list.assert_called_with( |
542 |
|
"vim_accounts", |
543 |
|
{"_id": nslcmop_record_wo_pinning["operationParams"]["validVimAccounts"]}, |
544 |
|
) |
545 |
|
|
546 |
1 |
def test__get_vnf_price_list(self): |
547 |
1 |
server = self.serverSetup() |
548 |
1 |
pl1 = server._get_vnf_price_list( |
549 |
|
Path(self._adjust_path("./vnf_price_list.yaml")) |
550 |
|
) |
551 |
1 |
self.assertIs(type(pl1), dict, "price list not a dictionary") |
552 |
1 |
for k, v in pl1.items(): |
553 |
1 |
self.assertIs(type(v), dict, "price list values not a dict") |
554 |
|
|
555 |
1 |
pl2 = server._get_vnf_price_list( |
556 |
|
Path(self._adjust_path("./vnf_price_list_keys.yaml")), "hackfest_project_a" |
557 |
|
) |
558 |
1 |
self.assertIs(type(pl2), dict, "price list not a dictionary") |
559 |
1 |
for k, v in pl2.items(): |
560 |
1 |
self.assertIs(type(v), dict, "price list values not a dict") |
561 |
1 |
self.assertEqual(pl1, pl2, "non-project and project price lists differ") |
562 |
|
|
563 |
1 |
def test__get_pil_info(self): |
564 |
1 |
server = self.serverSetup() |
565 |
1 |
ppi = server._get_pil_info(Path(self._adjust_path("./pil_price_list.yaml"))) |
566 |
1 |
self.assertIs(type(ppi), dict, "pil is not a dict") |
567 |
1 |
self.assertIn("pil", ppi.keys(), "pil has no pil key") |
568 |
1 |
self.assertIs(type(ppi["pil"]), list, "pil does not contain a list") |
569 |
|
# check for expected keys |
570 |
1 |
expected_keys = { |
571 |
|
"pil_description", |
572 |
|
"pil_price", |
573 |
|
"pil_latency", |
574 |
|
"pil_jitter", |
575 |
|
"pil_endpoints", |
576 |
|
} |
577 |
1 |
self.assertEqual(expected_keys, ppi["pil"][0].keys(), "expected keys not found") |
578 |
|
|
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"]} |
587 |
|
# ) |
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") |
591 |
|
|
592 |
1 |
@mock.patch.object( |
593 |
|
NsPlacementDataFactory, "__init__", lambda x0, x1, x2, x3, x4, x5, x6: None |
594 |
|
) |
595 |
1 |
@mock.patch.object(MznPlacementConductor, "do_placement_computation") |
596 |
1 |
@mock.patch.object(NsPlacementDataFactory, "create_ns_placement_data") |
597 |
1 |
@mock.patch.object(Server, "_get_vim_accounts") |
598 |
1 |
@mock.patch.object(Server, "_get_nsd") |
599 |
1 |
@mock.patch.object(Server, "_get_nslcmop") |
600 |
1 |
@mock.patch.object(Server, "_get_vnf_price_list") |
601 |
1 |
@mock.patch.object(Server, "_get_pil_info") |
602 |
1 |
@mock.patch.object(Server, "_get_projects") |
603 |
1 |
def test_get_placement( |
604 |
|
self, |
605 |
|
mock_get_projects, |
606 |
|
mock_get_pil_info, |
607 |
|
mock_get_vnf_price_list, |
608 |
|
mock__get_nslcmop, |
609 |
|
mock__get_nsd, |
610 |
|
mock__get_vim_accounts, |
611 |
|
mock_create_ns_placement_data, |
612 |
|
mock_do_placement_computation, |
613 |
|
): |
614 |
|
""" |
615 |
|
run _get_placement and check that things get called as expected |
616 |
|
:return: |
617 |
|
""" |
618 |
1 |
placement_ret_val = [ |
619 |
|
{ |
620 |
|
"vimAccountId": "bbbbbbbb-38f5-438d-b8ee-3f93b3531f87", |
621 |
|
"member-vnf-index": "VNF0", |
622 |
|
}, |
623 |
|
{ |
624 |
|
"vimAccountId": "aaaaaaaa-38f5-438d-b8ee-3f93b3531f87", |
625 |
|
"member-vnf-index": "VNF1", |
626 |
|
}, |
627 |
|
{ |
628 |
|
"vimAccountId": "aaaaaaaa-38f5-438d-b8ee-3f93b3531f87", |
629 |
|
"member-vnf-index": "VNF2", |
630 |
|
}, |
631 |
|
] |
632 |
1 |
server = self.serverSetup() |
633 |
|
|
634 |
1 |
server.msgBus.aiowrite = _async_mock() |
635 |
1 |
nsd_for_test = copy.deepcopy(nsd_from_db) |
636 |
1 |
mock__get_nsd.return_value = nsd_for_test |
637 |
1 |
mock__get_vim_accounts.return_value = list_of_vims |
638 |
|
|
639 |
|
# FIXME need update to match nslcmop, not for test but for consistency |
640 |
1 |
mock_do_placement_computation.return_value = placement_ret_val |
641 |
1 |
_run(server.get_placement(nslcmop_record_wo_pinning["id"])) |
642 |
|
|
643 |
1 |
self.assertTrue( |
644 |
|
mock_get_projects.called, "_get_projects not called as expected" |
645 |
|
) |
646 |
1 |
self.assertTrue( |
647 |
|
mock_get_vnf_price_list.called, "_get_vnf_price_list not called as expected" |
648 |
|
) |
649 |
1 |
self.assertTrue( |
650 |
|
mock_get_pil_info.called, "_get_pil_info not called as expected" |
651 |
|
) |
652 |
1 |
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 |
1 |
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 |
656 |
1 |
self.assertTrue( |
657 |
|
mock__get_vim_accounts.called, "get_vim_accounts not called as expected" |
658 |
|
) |
659 |
|
# mock_create_ns_placement_data.assert_called_once() assert_called_once() for python > 3.5 |
660 |
1 |
self.assertTrue( |
661 |
|
mock_create_ns_placement_data.called, |
662 |
|
"create_ns_placement_data not called as expected", |
663 |
|
) |
664 |
|
# mock_do_placement_computation.assert_called_once() assert_called_once() for python > 3.5 |
665 |
1 |
self.assertTrue( |
666 |
|
mock_do_placement_computation.called, |
667 |
|
"do_placement_computation not called as expected", |
668 |
|
) |
669 |
1 |
self.assertTrue(server.msgBus.aiowrite.mock.called) |
670 |
|
|
671 |
1 |
args, kwargs = server.msgBus.aiowrite.mock.call_args |
672 |
1 |
self.assertTrue(len(args) == 3, "invalid format") |
673 |
1 |
self.assertEqual("pla", args[0], "topic invalid") |
674 |
1 |
self.assertEqual("placement", args[1], "message invalid") |
675 |
|
# extract placement result and check content |
676 |
1 |
rsp_payload = args[2] |
677 |
|
|
678 |
1 |
expected_rsp_keys = {"placement"} |
679 |
1 |
self.assertEqual( |
680 |
|
expected_rsp_keys, |
681 |
|
set(rsp_payload.keys()), |
682 |
|
"placement response missing keys", |
683 |
|
) |
684 |
1 |
self.assertIs(type(rsp_payload["placement"]), dict, "placement not a dict") |
685 |
|
|
686 |
1 |
expected_placement_keys = {"vnf", "nslcmopId"} |
687 |
1 |
self.assertEqual( |
688 |
|
expected_placement_keys, |
689 |
|
set(rsp_payload["placement"]), |
690 |
|
"placement keys invalid", |
691 |
|
) |
692 |
|
|
693 |
1 |
vim_account_candidates = [e["vimAccountId"] for e in placement_ret_val] |
694 |
|
|
695 |
1 |
self.assertEqual( |
696 |
|
nslcmop_record_wo_pinning["id"], |
697 |
|
rsp_payload["placement"]["nslcmopId"], |
698 |
|
"nslcmopId invalid", |
699 |
|
) |
700 |
|
|
701 |
1 |
self.assertIs(type(rsp_payload["placement"]["vnf"]), list, "vnf not a list") |
702 |
1 |
expected_vnf_keys = {"vimAccountId", "member-vnf-index"} |
703 |
1 |
self.assertEqual( |
704 |
|
expected_vnf_keys, |
705 |
|
set(rsp_payload["placement"]["vnf"][0]), |
706 |
|
"placement['vnf'] missing keys", |
707 |
|
) |
708 |
1 |
self.assertIn( |
709 |
|
rsp_payload["placement"]["vnf"][0]["vimAccountId"], |
710 |
|
vim_account_candidates, |
711 |
|
"vimAccountId invalid", |
712 |
|
) |
713 |
|
|
714 |
1 |
@mock.patch.object( |
715 |
|
NsPlacementDataFactory, "__init__", lambda x0, x1, x2, x3, x4, x5, x6: None |
716 |
|
) |
717 |
1 |
@mock.patch.object(MznPlacementConductor, "do_placement_computation") |
718 |
1 |
@mock.patch.object(NsPlacementDataFactory, "create_ns_placement_data") |
719 |
1 |
@mock.patch.object(Server, "_get_vim_accounts") |
720 |
1 |
@mock.patch.object(Server, "_get_nsd") |
721 |
1 |
@mock.patch.object(Server, "_get_nslcmop") |
722 |
1 |
@mock.patch.object(Server, "_get_vnf_price_list") |
723 |
1 |
@mock.patch.object(Server, "_get_pil_info") |
724 |
1 |
@mock.patch.object(Server, "_get_projects") |
725 |
1 |
def test_get_placement_with_pinning( |
726 |
|
self, |
727 |
|
mock_get_projects, |
728 |
|
mock_get_pil_info, |
729 |
|
mock_get_vnf_price_list, |
730 |
|
mock__get_nslcmop, |
731 |
|
mock__get_nsd, |
732 |
|
mock__get_vim_accounts, |
733 |
|
mock_create_ns_placement_data, |
734 |
|
mock_do_placement_computation, |
735 |
|
): |
736 |
|
""" |
737 |
|
run _get_placement and check that things get called as expected |
738 |
|
:return: |
739 |
|
""" |
740 |
1 |
placement_ret_val = [ |
741 |
|
{ |
742 |
|
"vimAccountId": "bbbbbbbb-38f5-438d-b8ee-3f93b3531f87", |
743 |
|
"member-vnf-index": "VNF0", |
744 |
|
}, |
745 |
|
{ |
746 |
|
"vimAccountId": "aaaaaaaa-38f5-438d-b8ee-3f93b3531f87", |
747 |
|
"member-vnf-index": "VNF1", |
748 |
|
}, |
749 |
|
{ |
750 |
|
"vimAccountId": "aaaaaaaa-38f5-438d-b8ee-3f93b3531f87", |
751 |
|
"member-vnf-index": "VNF2", |
752 |
|
}, |
753 |
|
] |
754 |
1 |
server = self.serverSetup() |
755 |
|
|
756 |
1 |
server.msgBus.aiowrite = _async_mock() |
757 |
1 |
nsd_for_test = copy.deepcopy(nsd_from_db) |
758 |
1 |
mock__get_nsd.return_value = nsd_for_test |
759 |
1 |
mock__get_vim_accounts.return_value = list_of_vims |
760 |
|
|
761 |
|
# FIXME need update to match nslcmop, not for test but for consistency |
762 |
1 |
mock_do_placement_computation.return_value = placement_ret_val |
763 |
1 |
_run(server.get_placement(nslcmop_record_w_pinning["id"])) |
764 |
|
|
765 |
1 |
self.assertTrue( |
766 |
|
(mock_get_projects.called, "_get_projects not called as expected") |
767 |
|
) |
768 |
1 |
self.assertTrue( |
769 |
|
mock_get_vnf_price_list.called, "_get_vnf_price_list not called as expected" |
770 |
|
) |
771 |
1 |
self.assertTrue( |
772 |
|
mock_get_pil_info.called, "_get_pil_info not called as expected" |
773 |
|
) |
774 |
1 |
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 |
1 |
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 |
778 |
1 |
self.assertTrue( |
779 |
|
mock__get_vim_accounts.called, "get_vim_accounts not called as expected" |
780 |
|
) |
781 |
|
# mock_create_ns_placement_data.assert_called_once() assert_called_once() for python > 3.5 |
782 |
1 |
self.assertTrue( |
783 |
|
mock_create_ns_placement_data.called, |
784 |
|
"create_ns_placement_data not called as expected", |
785 |
|
) |
786 |
|
# mock_do_placement_computation.assert_called_once() assert_called_once() for python > 3.5 |
787 |
1 |
self.assertTrue( |
788 |
|
mock_do_placement_computation.called, |
789 |
|
"do_placement_computation not called as expected", |
790 |
|
) |
791 |
1 |
self.assertTrue(server.msgBus.aiowrite.mock.called) |
792 |
|
|
793 |
1 |
args, kwargs = server.msgBus.aiowrite.mock.call_args |
794 |
1 |
self.assertTrue(len(args) == 3, "invalid format") |
795 |
1 |
self.assertEqual("pla", args[0], "topic invalid") |
796 |
1 |
self.assertEqual("placement", args[1], "message invalid") |
797 |
|
# extract placement result and check content |
798 |
1 |
rsp_payload = args[2] |
799 |
|
|
800 |
1 |
expected_rsp_keys = {"placement"} |
801 |
1 |
self.assertEqual( |
802 |
|
expected_rsp_keys, |
803 |
|
set(rsp_payload.keys()), |
804 |
|
"placement response missing keys", |
805 |
|
) |
806 |
1 |
self.assertIs(type(rsp_payload["placement"]), dict, "placement not a dict") |
807 |
|
|
808 |
1 |
expected_placement_keys = {"vnf", "nslcmopId"} |
809 |
1 |
self.assertEqual( |
810 |
|
expected_placement_keys, |
811 |
|
set(rsp_payload["placement"]), |
812 |
|
"placement keys invalid", |
813 |
|
) |
814 |
|
|
815 |
1 |
vim_account_candidates = [e["vimAccountId"] for e in placement_ret_val] |
816 |
|
|
817 |
1 |
self.assertEqual( |
818 |
|
nslcmop_record_w_pinning["id"], |
819 |
|
rsp_payload["placement"]["nslcmopId"], |
820 |
|
"nslcmopId invalid", |
821 |
|
) |
822 |
|
|
823 |
1 |
self.assertIs(type(rsp_payload["placement"]["vnf"]), list, "vnf not a list") |
824 |
1 |
expected_vnf_keys = {"vimAccountId", "member-vnf-index"} |
825 |
1 |
self.assertEqual( |
826 |
|
expected_vnf_keys, |
827 |
|
set(rsp_payload["placement"]["vnf"][0]), |
828 |
|
"placement['vnf'] missing keys", |
829 |
|
) |
830 |
1 |
self.assertIn( |
831 |
|
rsp_payload["placement"]["vnf"][0]["vimAccountId"], |
832 |
|
vim_account_candidates, |
833 |
|
"vimAccountId invalid", |
834 |
|
) |
835 |
|
|
836 |
|
# Note: does not mock reading of price list and pil_info |
837 |
1 |
@mock.patch.object( |
838 |
|
NsPlacementDataFactory, "__init__", lambda x0, x1, x2, x3, x4, x5: None |
839 |
|
) |
840 |
1 |
@mock.patch.object(MznPlacementConductor, "do_placement_computation") |
841 |
1 |
@mock.patch.object(NsPlacementDataFactory, "create_ns_placement_data") |
842 |
1 |
@mock.patch.object(Server, "_get_vim_accounts") |
843 |
1 |
@mock.patch.object(Server, "_get_nsd") |
844 |
1 |
@mock.patch.object(Server, "_get_nslcmop") |
845 |
1 |
def test_get_placement_w_exception( |
846 |
|
self, |
847 |
|
mock__get_nslcmop, |
848 |
|
mock__get_nsd, |
849 |
|
mock__get_vim_accounts, |
850 |
|
mock_create_ns_placement_data, |
851 |
|
mock_do_placement_computation, |
852 |
|
): |
853 |
|
""" |
854 |
|
check that raised exceptions are handled and response provided accordingly |
855 |
|
""" |
856 |
1 |
server = self.serverSetup() |
857 |
|
|
858 |
1 |
server.msgBus.aiowrite = _async_mock() |
859 |
1 |
nsd_for_test = copy.deepcopy(nsd_from_db) |
860 |
1 |
mock__get_nsd.return_value = nsd_for_test |
861 |
1 |
mock__get_nsd.side_effect = RuntimeError("kaboom!") |
862 |
1 |
mock__get_vim_accounts.return_value = list_of_vims |
863 |
1 |
mock_do_placement_computation.return_value = [ |
864 |
|
{ |
865 |
|
"vimAccountId": "bbbbbbbb-38f5-438d-b8ee-3f93b3531f87", |
866 |
|
"member-vnf-index": "1", |
867 |
|
}, |
868 |
|
{ |
869 |
|
"vimAccountId": "aaaaaaaa-38f5-438d-b8ee-3f93b3531f87", |
870 |
|
"member-vnf-index": "2", |
871 |
|
}, |
872 |
|
{ |
873 |
|
"vimAccountId": "aaaaaaaa-38f5-438d-b8ee-3f93b3531f87", |
874 |
|
"member-vnf-index": "3", |
875 |
|
}, |
876 |
|
] |
877 |
|
|
878 |
1 |
_run(server.get_placement(nslcmop_record_w_pinning["id"])) |
879 |
1 |
self.assertTrue(server.msgBus.aiowrite.mock.called) |
880 |
1 |
args, kwargs = server.msgBus.aiowrite.mock.call_args |
881 |
1 |
rsp_payload = args[2] |
882 |
1 |
expected_keys = {"placement"} |
883 |
1 |
self.assertEqual( |
884 |
|
expected_keys, set(rsp_payload.keys()), "placement response missing keys" |
885 |
|
) |
886 |
1 |
self.assertIs(type(rsp_payload["placement"]["vnf"]), list, "vnf not a list") |
887 |
1 |
self.assertEqual([], rsp_payload["placement"]["vnf"], "vnf list not empty") |
888 |
1 |
self.assertEqual( |
889 |
|
nslcmop_record_w_pinning["id"], |
890 |
|
rsp_payload["placement"]["nslcmopId"], |
891 |
|
"nslcmopId invalid", |
892 |
|
) |