Adapts PLA to new SOL006 NSD descriptors format
[osm/PLA.git] / osm_pla / test / test_nsPlacementDataFactory.py
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 import os
16 import unittest
17 from collections import Counter
18 from pathlib import Path
19 from unittest import TestCase, mock
20 from unittest.mock import call
21
22 import yaml
23
24 from osm_pla.placement.mznplacement import NsPlacementDataFactory
25
26
27 class TestNsPlacementDataFactory(TestCase):
28 vim_accounts = [{"vim_password": "FxtnynxBCnouzAT4Hkerhg==", "config": {},
29 "_admin": {"modified": 1564579854.0480285, "created": 1564579854.0480285,
30 "operationalState": "ENABLED",
31 "projects_read": ["69915588-e5e2-46d3-96b0-a29bedef6f73"],
32 "deployed": {"RO-account": "6beb4e2e-b397-11e9-a7a3-02420aff0008",
33 "RO": "6bcfc3fc-b397-11e9-a7a3-02420aff0008"},
34 "projects_write": ["69915588-e5e2-46d3-96b0-a29bedef6f73"], "detailed-status": "Done"},
35 "name": "OpenStack1", "vim_type": "openstack", "_id": "92b056a7-38f5-438d-b8ee-3f93b3531f87",
36 "schema_version": "1.1", "vim_user": "admin", "vim_url": "http://10.234.12.47:5000/v3",
37 "vim_tenant_name": "admin"},
38 {"config": {}, "vim_tenant_name": "osm_demo", "schema_version": "1.1", "name": "OpenStack2",
39 "vim_password": "gK5v4Gh2Pl41o6Skwp6RCw==", "vim_type": "openstack",
40 "_admin": {"modified": 1567148372.2490237, "created": 1567148372.2490237,
41 "operationalState": "ENABLED",
42 "projects_read": ["69915588-e5e2-46d3-96b0-a29bedef6f73"],
43 "deployed": {"RO-account": "b7fb0034-caf3-11e9-9388-02420aff000a",
44 "RO": "b7f129ce-caf3-11e9-9388-02420aff000a"},
45 "projects_write": ["69915588-e5e2-46d3-96b0-a29bedef6f73"], "detailed-status": "Done"},
46 "vim_user": "admin", "vim_url": "http://10.234.12.44:5000/v3",
47 "_id": "6618d412-d7fc-4eb0-a6f8-d2c258e0e900"},
48 {"config": {}, "schema_version": "1.1", "name": "OpenStack3",
49 "vim_password": "1R2FoMQnaL6rNSosoRP2hw==", "vim_type": "openstack", "vim_tenant_name": "osm_demo",
50 "_admin": {"modified": 1567599746.689582, "created": 1567599746.689582,
51 "operationalState": "ENABLED",
52 "projects_read": ["69915588-e5e2-46d3-96b0-a29bedef6f73"],
53 "deployed": {"RO-account": "a8161f54-cf0e-11e9-9388-02420aff000a",
54 "RO": "a80b6280-cf0e-11e9-9388-02420aff000a"},
55 "projects_write": ["69915588-e5e2-46d3-96b0-a29bedef6f73"], "detailed-status": "Done"},
56 "vim_user": "admin", "vim_url": "http://10.234.12.46:5000/v3",
57 "_id": "331ffdec-44a8-4707-94a1-af7a292d9735"},
58 {"config": {}, "schema_version": "1.1", "name": "OpenStack4",
59 "vim_password": "6LScyPeMq3QFh3GRb/xwZw==", "vim_type": "openstack", "vim_tenant_name": "osm_demo",
60 "_admin": {"modified": 1567599911.5108898, "created": 1567599911.5108898,
61 "operationalState": "ENABLED",
62 "projects_read": ["69915588-e5e2-46d3-96b0-a29bedef6f73"],
63 "deployed": {"RO-account": "0a651200-cf0f-11e9-9388-02420aff000a",
64 "RO": "0a4defc6-cf0f-11e9-9388-02420aff000a"},
65 "projects_write": ["69915588-e5e2-46d3-96b0-a29bedef6f73"], "detailed-status": "Done"},
66 "vim_user": "admin", "vim_url": "http://10.234.12.43:5000/v3",
67 "_id": "eda92f47-29b9-4007-9709-c1833dbfbe31"}]
68
69 vim_accounts_fewer_vims = [{"vim_password": "FxtnynxBCnouzAT4Hkerhg==", "config": {},
70 "_admin": {"modified": 1564579854.0480285, "created": 1564579854.0480285,
71 "operationalState": "ENABLED",
72 "projects_read": ["69915588-e5e2-46d3-96b0-a29bedef6f73"],
73 "deployed": {"RO-account": "6beb4e2e-b397-11e9-a7a3-02420aff0008",
74 "RO": "6bcfc3fc-b397-11e9-a7a3-02420aff0008"},
75 "projects_write": ["69915588-e5e2-46d3-96b0-a29bedef6f73"],
76 "detailed-status": "Done"},
77 "name": "OpenStack1", "vim_type": "openstack",
78 "_id": "92b056a7-38f5-438d-b8ee-3f93b3531f87",
79 "schema_version": "1.1", "vim_user": "admin", "vim_url": "http://10.234.12.47:5000/v3",
80 "vim_tenant_name": "admin"},
81 {"config": {}, "vim_tenant_name": "osm_demo", "schema_version": "1.1",
82 "name": "OpenStack2",
83 "vim_password": "gK5v4Gh2Pl41o6Skwp6RCw==", "vim_type": "openstack",
84 "_admin": {"modified": 1567148372.2490237, "created": 1567148372.2490237,
85 "operationalState": "ENABLED",
86 "projects_read": ["69915588-e5e2-46d3-96b0-a29bedef6f73"],
87 "deployed": {"RO-account": "b7fb0034-caf3-11e9-9388-02420aff000a",
88 "RO": "b7f129ce-caf3-11e9-9388-02420aff000a"},
89 "projects_write": ["69915588-e5e2-46d3-96b0-a29bedef6f73"],
90 "detailed-status": "Done"},
91 "vim_user": "admin", "vim_url": "http://10.234.12.44:5000/v3",
92 "_id": "6618d412-d7fc-4eb0-a6f8-d2c258e0e900"},
93 {"config": {}, "schema_version": "1.1", "name": "OpenStack4",
94 "vim_password": "6LScyPeMq3QFh3GRb/xwZw==", "vim_type": "openstack",
95 "vim_tenant_name": "osm_demo",
96 "_admin": {"modified": 1567599911.5108898, "created": 1567599911.5108898,
97 "operationalState": "ENABLED",
98 "projects_read": ["69915588-e5e2-46d3-96b0-a29bedef6f73"],
99 "deployed": {"RO-account": "0a651200-cf0f-11e9-9388-02420aff000a",
100 "RO": "0a4defc6-cf0f-11e9-9388-02420aff000a"},
101 "projects_write": ["69915588-e5e2-46d3-96b0-a29bedef6f73"],
102 "detailed-status": "Done"},
103 "vim_user": "admin", "vim_url": "http://10.234.12.43:5000/v3",
104 "_id": "eda92f47-29b9-4007-9709-c1833dbfbe31"}]
105
106 vim_accounts_more_vims = [{"vim_password": "FxtnynxBCnouzAT4Hkerhg==", "config": {},
107 "_admin": {"modified": 1564579854.0480285, "created": 1564579854.0480285,
108 "operationalState": "ENABLED",
109 "projects_read": ["69915588-e5e2-46d3-96b0-a29bedef6f73"],
110 "deployed": {"RO-account": "6beb4e2e-b397-11e9-a7a3-02420aff0008",
111 "RO": "6bcfc3fc-b397-11e9-a7a3-02420aff0008"},
112 "projects_write": ["69915588-e5e2-46d3-96b0-a29bedef6f73"],
113 "detailed-status": "Done"},
114 "name": "OpenStack1", "vim_type": "openstack",
115 "_id": "92b056a7-38f5-438d-b8ee-3f93b3531f87",
116 "schema_version": "1.1", "vim_user": "admin", "vim_url": "http://10.234.12.47:5000/v3",
117 "vim_tenant_name": "admin"},
118 {"config": {}, "vim_tenant_name": "osm_demo", "schema_version": "1.1",
119 "name": "OpenStack2",
120 "vim_password": "gK5v4Gh2Pl41o6Skwp6RCw==", "vim_type": "openstack",
121 "_admin": {"modified": 1567148372.2490237, "created": 1567148372.2490237,
122 "operationalState": "ENABLED",
123 "projects_read": ["69915588-e5e2-46d3-96b0-a29bedef6f73"],
124 "deployed": {"RO-account": "b7fb0034-caf3-11e9-9388-02420aff000a",
125 "RO": "b7f129ce-caf3-11e9-9388-02420aff000a"},
126 "projects_write": ["69915588-e5e2-46d3-96b0-a29bedef6f73"],
127 "detailed-status": "Done"},
128 "vim_user": "admin", "vim_url": "http://10.234.12.44:5000/v3",
129 "_id": "6618d412-d7fc-4eb0-a6f8-d2c258e0e900"},
130 {"config": {}, "schema_version": "1.1", "name": "OpenStack4",
131 "vim_password": "6LScyPeMq3QFh3GRb/xwZw==", "vim_type": "openstack",
132 "vim_tenant_name": "osm_demo",
133 "_admin": {"modified": 1567599911.5108898, "created": 1567599911.5108898,
134 "operationalState": "ENABLED",
135 "projects_read": ["69915588-e5e2-46d3-96b0-a29bedef6f73"],
136 "deployed": {"RO-account": "0a651200-cf0f-11e9-9388-02420aff000a",
137 "RO": "0a4defc6-cf0f-11e9-9388-02420aff000a"},
138 "projects_write": ["69915588-e5e2-46d3-96b0-a29bedef6f73"],
139 "detailed-status": "Done"},
140 "vim_user": "admin", "vim_url": "http://10.234.12.43:5000/v3",
141 "_id": "eda92f47-29b9-4007-9709-c1833dbfbe31"},
142 {"config": {}, "schema_version": "1.1", "name": "OpenStack3",
143 "vim_password": "6LScyPeMq3QFh3GRb/xwZw==", "vim_type": "openstack",
144 "vim_tenant_name": "osm_demo",
145 "_admin": {"modified": 1567599911.5108898, "created": 1567599911.5108898,
146 "operationalState": "ENABLED",
147 "projects_read": ["69915588-e5e2-46d3-96b0-a29bedef6f73"],
148 "deployed": {"RO-account": "0a651200-cf0f-11e9-9388-02420aff000a",
149 "RO": "0a4defc6-cf0f-11e9-9388-02420aff000a"},
150 "projects_write": ["69915588-e5e2-46d3-96b0-a29bedef6f73"],
151 "detailed-status": "Done"},
152 "vim_user": "admin", "vim_url": "http://10.234.12.46:5000/v3",
153 "_id": "eda92f47-29b9-4007-9709-c1833dbfbe31"},
154 {"config": {}, "schema_version": "1.1", "name": "OpenStack5",
155 "vim_password": "6LScyPeMq3QFh3GRb/xwZw==", "vim_type": "openstack",
156 "vim_tenant_name": "osm_demo",
157 "_admin": {"modified": 1567599911.5108898, "created": 1567599911.5108898,
158 "operationalState": "ENABLED",
159 "projects_read": ["69915588-e5e2-46d3-96b0-a29bedef6f73"],
160 "deployed": {"RO-account": "0a651200-cf0f-11e9-9388-02420aff000a",
161 "RO": "0a4defc6-cf0f-11e9-9388-02420aff000a"},
162 "projects_write": ["69915588-e5e2-46d3-96b0-a29bedef6f73"],
163 "detailed-status": "Done"},
164 "vim_user": "admin", "vim_url": "http://1.1.1.1:5000/v3",
165 "_id": "ffffffff-29b9-4007-9709-c1833dbfbe31"}]
166
167 def _produce_ut_vim_accounts_info(self, vim_accounts):
168 """
169 FIXME temporary, we will need more control over vim_urls and _id for test purpose - make a generator
170 :return: vim_url and _id as dict, i.e. extract these from vim_accounts data
171 """
172 return {_['name']: _['_id'] for _ in vim_accounts}
173
174 def _adjust_path(self, file):
175 """In case we are not running from test directory,
176 then assume we are in top level directory (e.g. running from tox) and adjust file path accordingly"""
177 path_component = '/osm_pla/test/'
178 real_path = os.path.realpath(file)
179 if path_component not in real_path:
180 return os.path.dirname(real_path) + path_component + os.path.basename(real_path)
181 else:
182 return real_path
183
184 def _populate_pil_info(self, file):
185 """
186 Note str(Path()) is a 3.5 thing
187 """
188 with open(str(Path(self._adjust_path(file)))) as pp_fd:
189 test_data = yaml.safe_load_all(pp_fd)
190 return next(test_data)
191
192 def _get_ut_nsd_from_file(self, nsd_file_name):
193 """
194 creates the structure representing the nsd.
195
196 IMPORTANT NOTE: If using .yaml files from the NS packages for the unit tests (which we do),
197 then the files must be modified with respect to the way booleans are processed at on-boarding in OSM.
198 The following construct in the NS package yaml file:
199 mgmt-network: 'false'
200 will become a boolean in the MongoDB, and therefore the yaml used in these unit test must use yaml
201 tag as follows:
202 mgmt-network: !!bool False
203 The modification also applies to 'true' => !!bool True
204 This will ensure that the object returned from this function is as expected by PLA.
205 """
206 with open(str(Path(self._adjust_path(nsd_file_name)))) as nsd_fd:
207 test_data = yaml.safe_load_all(nsd_fd)
208 return next(test_data)
209
210 def _produce_ut_vnf_price_list(self):
211 price_list_file = "vnf_price_list.yaml"
212 with open(str(Path(self._adjust_path(price_list_file)))) as pl_fd:
213 price_list_data = yaml.safe_load_all(pl_fd)
214 return {i['vnfd']: {i1['vim_name']: i1['price'] for i1 in i['prices']} for i in next(price_list_data)}
215
216 def _produce_ut_vnf_test_price_list(self, price_list):
217 price_list_file = price_list
218 with open(str(Path(self._adjust_path(price_list_file)))) as pl_fd:
219 price_list_data = yaml.safe_load_all(pl_fd)
220 return {i['vnfd']: {i1['vim_name']: i1['price'] for i1 in i['prices']} for i in next(price_list_data)}
221
222 def test__produce_trp_link_characteristics_link_latency_with_more_vims(self):
223 """
224 -test with more(other) vims compared to pil
225 """
226 content_expected = [0, 0, 0, 0, 0, 120, 120, 130, 130, 140, 140, 230, 230, 240, 240,
227 340, 340, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767]
228 nspdf = NsPlacementDataFactory(
229 self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts_more_vims),
230 self._produce_ut_vnf_price_list(),
231 nsd=None,
232 pil_info=self._populate_pil_info('pil_unittest1_keys.yaml'),
233 pinning=None)
234 pil_latencies = nspdf._produce_trp_link_characteristics_data('pil_latency')
235 content_produced = [i for row in pil_latencies for i in row]
236 self.assertEqual(Counter(content_expected), Counter(content_produced), 'trp_link_latency incorrect')
237
238 def test__produce_trp_link_characteristics_link_latency_with_fewer_vims(self):
239 """
240 -test with fewer vims compared to pil
241 :return:
242 """
243 content_expected = [0, 0, 0, 120, 120, 140, 140, 240, 240]
244 nspdf = NsPlacementDataFactory(
245 self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts_fewer_vims),
246 self._produce_ut_vnf_price_list(),
247 nsd=None,
248 pil_info=self._populate_pil_info('pil_unittest1_keys.yaml'),
249 pinning=None)
250 pil_latencies = nspdf._produce_trp_link_characteristics_data('pil_latency')
251 content_produced = [i for row in pil_latencies for i in row]
252 self.assertEqual(Counter(content_expected), Counter(content_produced), 'trp_link_latency incorrect')
253
254 def test__produce_trp_link_characteristic_not_supported(self):
255 """
256 - test with non-supported characteristic
257 """
258 nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts),
259 self._produce_ut_vnf_price_list(),
260 nsd=None,
261 pil_info=self._populate_pil_info('pil_unittest1.yaml'), pinning=None)
262
263 with self.assertRaises(Exception) as e:
264 nspdf._produce_trp_link_characteristics_data('test_no_support')
265 self.assertRegex(str(e.exception), r'characteristic.*not supported', "invalid exception content")
266
267 def test__produce_trp_link_characteristics_link_latency(self):
268 """
269 -test with full set of vims as in pil
270 -test with fewer vims compared to pil
271 -test with more(other) vims compared to pil
272 -test with invalid/corrupt pil configuration file (e.g. missing endpoint), empty file, not yaml conformant
273 - test with non-supported characteristic
274
275 :return:
276 """
277 content_expected = [0, 0, 0, 0, 120, 120, 130, 130, 140, 140, 230, 230, 240, 240, 340, 340]
278
279 nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts),
280 self._produce_ut_vnf_price_list(),
281 nsd=None,
282 pil_info=self._populate_pil_info('pil_unittest1_keys.yaml'), pinning=None)
283 pil_latencies = nspdf._produce_trp_link_characteristics_data('pil_latency')
284 content_produced = [i for row in pil_latencies for i in row]
285 self.assertEqual(Counter(content_expected), Counter(content_produced), 'trp_link_latency incorrect')
286
287 def test__produce_trp_link_characteristics_link_jitter(self):
288 """
289 -test with full set of vims as in pil
290 """
291 content_expected = [0, 0, 0, 0, 1200, 1200, 1300, 1300, 1400, 1400, 2300, 2300, 2400, 2400, 3400, 3400]
292
293 nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts),
294 self._produce_ut_vnf_price_list(),
295 nsd=None,
296 pil_info=self._populate_pil_info('pil_unittest1_keys.yaml'), pinning=None)
297 pil_jitter = nspdf._produce_trp_link_characteristics_data('pil_jitter')
298 content_produced = [i for row in pil_jitter for i in row]
299 self.assertEqual(Counter(content_expected), Counter(content_produced), 'trp_link_jitter incorrect')
300
301 def test__produce_trp_link_characteristics_link_jitter_with_fewer_vims(self):
302 """
303 -test with fewer vims compared to pil, link jitter
304 """
305 content_expected = [0, 0, 0, 1200, 1200, 1400, 1400, 2400, 2400]
306 nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(self.vim_accounts_fewer_vims),
307 self._produce_ut_vnf_price_list(),
308 nsd=None,
309 pil_info=self._populate_pil_info('pil_unittest1_keys.yaml'), pinning=None)
310 pil_latencies = nspdf._produce_trp_link_characteristics_data('pil_jitter')
311 content_produced = [i for row in pil_latencies for i in row]
312 self.assertEqual(Counter(content_expected), Counter(content_produced), 'trp_link_jitter incorrect')
313
314 def test__produce_trp_link_characteristics_link_jitter_with_more_vims(self):
315 """
316 -test with more vims compared to pil, link jitter
317 """
318 content_expected = [0, 0, 0, 0, 0, 1200, 1200, 1300, 1300, 1400, 1400, 2300,
319 2300, 2400, 2400, 3400, 3400, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767]
320 nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(self.vim_accounts_more_vims),
321 self._produce_ut_vnf_price_list(),
322 nsd=None,
323 pil_info=self._populate_pil_info('pil_unittest1_keys.yaml'), pinning=None)
324 pil_latencies = nspdf._produce_trp_link_characteristics_data('pil_jitter')
325 content_produced = [i for row in pil_latencies for i in row]
326 self.assertEqual(Counter(content_expected), Counter(content_produced), 'trp_link_jitter incorrect')
327
328 def test__produce_trp_link_characteristics_link_price(self):
329 """
330 -test with full set of vims as in pil
331 """
332 content_expected = [0, 0, 0, 0, 12, 12, 13, 13, 14, 14, 23, 23, 24, 24, 34, 34]
333 nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts),
334 self._produce_ut_vnf_price_list(),
335 nsd=None,
336 pil_info=self._populate_pil_info('pil_unittest1_keys.yaml'), pinning=None)
337 pil_prices = nspdf._produce_trp_link_characteristics_data('pil_price')
338 content_produced = [i for row in pil_prices for i in row]
339 self.assertEqual(Counter(content_expected), Counter(content_produced), 'invalid trp link prices')
340
341 def test__produce_trp_link_characteristics_link_price_with_fewer_vims(self):
342 """
343 -test with fewer vims compared to pil
344 """
345 content_expected = [0, 0, 0, 12, 12, 14, 14, 24, 24]
346 nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(self.vim_accounts_fewer_vims),
347 self._produce_ut_vnf_price_list(),
348 nsd=None,
349 pil_info=self._populate_pil_info('pil_unittest1_keys.yaml'), pinning=None)
350 pil_prices = nspdf._produce_trp_link_characteristics_data('pil_price')
351 content_produced = [i for row in pil_prices for i in row]
352 self.assertEqual(Counter(content_expected), Counter(content_produced), 'invalid trp link prices')
353
354 def test__produce_trp_link_characteristics_partly_constrained(self):
355 content_expected = [0, 0, 0, 0, 32767, 32767, 32767, 32767, 1200, 1200, 1400, 1400, 2400, 2400, 3400, 3400]
356 nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts),
357 self._produce_ut_vnf_price_list(),
358 nsd=None,
359 pil_info=self._populate_pil_info('pil_unittest2_keys.yaml'), pinning=None)
360 pil_jitter = nspdf._produce_trp_link_characteristics_data('pil_jitter')
361 content_produced = [i for row in pil_jitter for i in row]
362 self.assertEqual(Counter(content_expected), Counter(content_produced),
363 'invalid trp link jitter, partly constrained')
364
365 def test__produce_vld_desc_partly_constrained(self):
366 vld_desc_expected = [{'cp_refs': ['one', 'two'], 'jitter': 30},
367 {'cp_refs': ['two', 'three'], 'latency': 120}]
368
369 nsd = self._get_ut_nsd_from_file('nsd_unittest2.yaml')
370 nsd = nsd['nsd']['nsd'][0]
371 nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts),
372 self._produce_ut_vnf_price_list(),
373 nsd=nsd,
374 pil_info=None, pinning=None)
375 self.assertEqual(vld_desc_expected, nspdf._produce_vld_desc(),
376 "vld_desc incorrect")
377
378 def test__produce_trp_link_characteristics_link_latency_not_yaml_conformant(self):
379 """
380 -test with invalid/corrupt pil configuration file (not yaml conformant)
381 """
382 with self.assertRaises(Exception) as e:
383 _ = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts),
384 self._produce_ut_vnf_price_list(),
385 nsd=None,
386 pil_info=self._populate_pil_info('not_yaml_conformant.yaml'),
387 pinning=None)
388 self.assertRegex(str(e.exception), r'mapping values are not allowed here.*', "invalid exception content")
389
390 def test__produce_trp_link_characteristics_with_invalid_pil_config(self):
391 """
392 -test with invalid/corrupt pil configuration file (missing endpoint)
393 """
394 nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts),
395 self._produce_ut_vnf_price_list(),
396 nsd=None,
397 pil_info=self._populate_pil_info('corrupt_pil_endpoints_config_unittest1.yaml'),
398 pinning=None)
399 with self.assertRaises(Exception) as e:
400 _ = nspdf._produce_trp_link_characteristics_data('pil_latency')
401 self.assertEqual('list index out of range', str(e.exception), "unexpected exception")
402
403 def test__produce_vld_desc_w_instantiate_override(self):
404
405 vld_desc_expected = [{'cp_refs': ['one', 'two'], 'latency': 150, 'jitter': 30},
406 {'cp_refs': ['two', 'three'], 'latency': 90, 'jitter': 30}]
407
408 nsd = self._get_ut_nsd_from_file('nsd_unittest_no_vld_constraints.yaml')
409 nsd = nsd['nsd']['nsd'][0]
410 nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts),
411 self._produce_ut_vnf_price_list(),
412 nsd=nsd,
413 pil_info=None, pinning=None,
414 order_constraints=None)
415
416 self.assertNotEqual(nspdf._produce_vld_desc(),
417 vld_desc_expected, "vld_desc incorrect")
418
419 def test__produce_vld_desc_nsd_w_instantiate_wo(self):
420 """
421 nsd w/ constraints, instantiate w/o constraints
422 :return:
423 """
424 vld_desc_expected = [{'cp_refs': ['one', 'two'], 'latency': 150, 'jitter': 30},
425 {'cp_refs': ['two', 'three'], 'latency': 90, 'jitter': 30}]
426
427 nsd = self._get_ut_nsd_from_file('nsd_unittest3.yaml')
428 nsd = nsd['nsd']['nsd'][0]
429 nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts),
430 self._produce_ut_vnf_price_list(),
431 nsd=nsd,
432 pil_info=None, pinning=None,
433 order_constraints=None)
434
435 self.assertEqual(vld_desc_expected, nspdf._produce_vld_desc(),
436 "vld_desc incorrect")
437
438 def test__produce_vld_desc_nsd_w_instantiate_w(self):
439 """
440 nsd w/ constraints, instantiate w/ constraints => override
441 :return:
442 """
443 vld_desc_expected = [{'cp_refs': ['one', 'two'], 'latency': 120, 'jitter': 21},
444 {'cp_refs': ['two', 'three'], 'latency': 121, 'jitter': 22}]
445
446 nsd = self._get_ut_nsd_from_file('nsd_unittest3.yaml')
447 nsd = nsd['nsd']['nsd'][0]
448 nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts),
449 self._produce_ut_vnf_price_list(),
450 nsd=nsd,
451 pil_info=None, pinning=None,
452 order_constraints={
453 'vld-constraints': [{'id': 'three_vnf_constrained_nsd_vld1',
454 'link-constraints': {'latency': 120,
455 'jitter': 21}},
456 {'id': 'three_vnf_constrained_nsd_vld2',
457 'link-constraints': {'latency': 121,
458 'jitter': 22}}]})
459
460 self.assertEqual(vld_desc_expected, nspdf._produce_vld_desc(),
461 "vld_desc incorrect")
462
463 def test__produce_vld_desc_nsd_wo_instantiate_wo(self):
464 """
465 nsd w/o constraints, instantiate w/o constraints = no constraints in model
466 :return:
467 """
468 vld_desc_expected = [{'cp_refs': ['one', 'two']},
469 {'cp_refs': ['two', 'three']}]
470
471 nsd = self._get_ut_nsd_from_file('nsd_unittest_no_vld_constraints.yaml')
472 nsd = nsd['nsd']['nsd'][0]
473 nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts),
474 self._produce_ut_vnf_price_list(),
475 nsd=nsd,
476 pil_info=None, pinning=None,
477 order_constraints=None)
478
479 self.assertEqual(vld_desc_expected, nspdf._produce_vld_desc(),
480 "vld_desc incorrect")
481
482 def test__produce_vld_desc_nsd_wo_instantiate_w(self):
483 """
484 nsd w/o constraints, instantiate w/ constraints => add constraints
485 :return:
486 """
487 vld_desc_expected = [{'cp_refs': ['one', 'two'], 'latency': 140, 'jitter': 41},
488 {'cp_refs': ['two', 'three'], 'latency': 141, 'jitter': 42}]
489
490 nsd = self._get_ut_nsd_from_file('nsd_unittest_no_vld_constraints.yaml')
491 nsd = nsd['nsd']['nsd'][0]
492 nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts),
493 self._produce_ut_vnf_price_list(),
494 nsd=nsd,
495 pil_info=None, pinning=None,
496 order_constraints={
497 'vld-constraints': [{'id': 'three_vnf_constrained_nsd_vld1',
498 'link-constraints': {'latency': 140,
499 'jitter': 41}},
500 {'id': 'three_vnf_constrained_nsd_vld2',
501 'link-constraints': {'latency': 141,
502 'jitter': 42}}]})
503
504 self.assertEqual(vld_desc_expected, nspdf._produce_vld_desc(),
505 "vld_desc incorrect")
506
507 def test__produce_vld_desc_nsd_wo_instantiate_w_faulty_input(self):
508 """
509 nsd w/o constraints, instantiate w/ constraints => add constraints that can be parsed
510 :return:
511 """
512 vld_desc_expected = [{'cp_refs': ['one', 'two']},
513 {'cp_refs': ['two', 'three'], 'latency': 151}]
514
515 nsd = self._get_ut_nsd_from_file('nsd_unittest_no_vld_constraints.yaml')
516 nsd = nsd['nsd']['nsd'][0]
517 nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts),
518 self._produce_ut_vnf_price_list(),
519 nsd=nsd,
520 pil_info=None, pinning=None,
521 order_constraints={'vld-constraints': [{'id': 'not_included_vld',
522 'misspelled-constraints':
523 {'latency': 120,
524 'jitter': 20}},
525 {'id': 'three_vnf_constrained_nsd_vld2',
526 'link-constraints': {
527 'latency': 151}}]})
528
529 self.assertEqual(vld_desc_expected, nspdf._produce_vld_desc(),
530 "vld_desc incorrect")
531
532 def test__produce_vld_desc_nsd_wo_instantiate_w_faulty_input_again(self):
533 """
534 nsd w/o constraints, instantiate w/ faulty constraints => add constraints that can be parsed
535 :return:
536 """
537 vld_desc_expected = [{'cp_refs': ['one', 'two'], 'jitter': 21},
538 {'cp_refs': ['two', 'three']}]
539
540 nsd = self._get_ut_nsd_from_file('nsd_unittest_no_vld_constraints.yaml')
541 nsd = nsd['nsd']['nsd'][0]
542 nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts),
543 self._produce_ut_vnf_price_list(),
544 nsd=nsd,
545 pil_info=None, pinning=None,
546 order_constraints={
547 'vld-constraints': [{'id': 'three_vnf_constrained_nsd_vld1',
548 'link-constraints': {'delay': 120,
549 'jitter': 21}},
550 {'id': 'three_vnf_constrained_nsd_vld2',
551 'misspelled-constraints': {'latency': 121,
552 'jitter': 22}}]})
553
554 self.assertEqual(vld_desc_expected, nspdf._produce_vld_desc(),
555 "vld_desc incorrect")
556
557 def test__produce_vld_desc_mgmt_network(self):
558 vld_desc_expected = [{'cp_refs': ['1', '2'], 'latency': 120, 'jitter': 20},
559 {'cp_refs': ['2', '4'], 'latency': 50, 'jitter': 10},
560 {'cp_refs': ['2', '3'], 'latency': 20, 'jitter': 10}, ]
561
562 nsd = self._get_ut_nsd_from_file('test_five_nsd.yaml')
563 nsd = nsd['nsd']['nsd'][0]
564 nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts),
565 self._produce_ut_vnf_price_list(),
566 nsd=nsd,
567 pil_info=None, pinning=None,
568 order_constraints=None)
569
570 self.assertEqual(vld_desc_expected, nspdf._produce_vld_desc(), "vld_desc incorrect")
571
572 def test__produce_vld_desc_single_vnf_nsd(self):
573 vld_desc_expected = []
574
575 nsd = self._get_ut_nsd_from_file('nsd_unittest4.yaml')
576 nsd = nsd['nsd']['nsd'][0]
577 nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts),
578 self._produce_ut_vnf_price_list(),
579 nsd=nsd,
580 pil_info=None, pinning=None,
581 order_constraints=None)
582
583 self.assertEqual(vld_desc_expected, nspdf._produce_vld_desc(), "vld_desc_incorrect")
584
585 def test__produce_vld_desc_slice_nsd(self):
586 vld_desc_expected = []
587 nsd = self._get_ut_nsd_from_file('slice_hackfest_middle_nsd.yaml')
588 nsd = nsd['nsd']['nsd'][0]
589 nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts),
590 self._produce_ut_vnf_price_list(),
591 nsd=nsd,
592 pil_info=None, pinning=None,
593 order_constraints=None)
594
595 self.assertEqual(vld_desc_expected, nspdf._produce_vld_desc(), "vld_desc_incorrect")
596
597 def test__produce_vld_desc(self):
598 """
599
600 :return:
601 """
602 vld_desc_expected = [{'cp_refs': ['one', 'two'], 'latency': 150, 'jitter': 30},
603 {'cp_refs': ['two', 'three'], 'latency': 90, 'jitter': 30}]
604
605 nsd = self._get_ut_nsd_from_file('nsd_unittest3.yaml')
606 nsd = nsd['nsd']['nsd'][0]
607 nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts),
608 self._produce_ut_vnf_price_list(),
609 nsd=nsd,
610 pil_info=None, pinning=None,
611 order_constraints=None)
612
613 self.assertEqual(vld_desc_expected, nspdf._produce_vld_desc(), "vld_desc incorrect")
614
615 def test__produce_ns_desc(self):
616 """
617 ToDo
618 - price list sheet with more vims than associated with session
619 - price list sheet with fewer vims than associated with session
620 - nsd with different vndfd-id-refs
621 - fault case scenarios with non-existing vims, non-existing vnfds
622 """
623 nsd = self._get_ut_nsd_from_file('nsd_unittest3.yaml')
624 nsd = nsd['nsd']['nsd'][0]
625 nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts),
626 self._produce_ut_vnf_price_list(),
627 nsd=nsd,
628 pil_info=None,
629 pinning=None)
630
631 ns_desc = nspdf._produce_ns_desc()
632 # check that all expected member-vnf-index are present
633 vnfs = [e['vnf_id'] for e in ns_desc]
634 self.assertEqual(Counter(['one', 'two', 'three']), Counter(vnfs), 'vnf_id invalid')
635
636 expected_keys = ['vnf_id', 'vnf_price_per_vim']
637 for e in ns_desc:
638 # check that vnf_price_per_vim has proper values
639 self.assertEqual(Counter([5, 10, 30, 30]), Counter(e['vnf_price_per_vim']), 'vnf_price_per_vim invalid')
640 # check that no pinning directives included
641 self.assertEqual(Counter(expected_keys), Counter(e.keys()), 'pinning directive misplaced')
642
643 def test__produce_ns_desc_with_more_vims(self):
644 nsd = self._get_ut_nsd_from_file('nsd_unittest1.yaml')
645 nsd = nsd['nsd']['nsd'][0]
646 nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(self.vim_accounts_more_vims),
647 self._produce_ut_vnf_test_price_list('vnf_price_list_more_vims.yaml'),
648 nsd=nsd,
649 pil_info=None,
650 pinning=None)
651
652 ns_desc = nspdf._produce_ns_desc()
653 # check that all expected member-vnf-index are present
654 vnfs = [e['vnf_id'] for e in ns_desc]
655 self.assertEqual(Counter({'1': 1, '2': 1, '3': 1}), Counter(vnfs), 'vnf_id invalid')
656
657 expected_keys = ['vnf_id', 'vnf_price_per_vim']
658 for e in ns_desc:
659 # check that vnf_price_per_vim has proper values
660 self.assertEqual(Counter([5, 10, 30, 30, 3]), Counter(e['vnf_price_per_vim']), 'vnf_price_per_vim invalid')
661 # check that no pinning directives included
662 self.assertEqual(Counter(expected_keys), Counter(e.keys()), 'pinning directive misplaced')
663
664 def test__produce_ns_desc_with_fewer_vims(self):
665 nsd = self._get_ut_nsd_from_file('nsd_unittest1.yaml')
666 nsd = nsd['nsd']['nsd'][0]
667 nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(self.vim_accounts_fewer_vims),
668 self._produce_ut_vnf_price_list(),
669 nsd=nsd,
670 pil_info=None,
671 pinning=None)
672
673 ns_desc = nspdf._produce_ns_desc()
674 # check that all expected member-vnf-index are present
675 vnfs = [e['vnf_id'] for e in ns_desc]
676 self.assertEqual(Counter({'1': 1, '2': 1, '3': 1}), Counter(vnfs), 'vnf_id invalid')
677
678 expected_keys = ['vnf_id', 'vnf_price_per_vim']
679 for e in ns_desc:
680 # check that vnf_price_per_vim has proper values
681 self.assertEqual(Counter([5, 10, 30]), Counter(e['vnf_price_per_vim']), 'vnf_price_per_vim invalid')
682 # check that no pinning directives included
683 self.assertEqual(Counter(expected_keys), Counter(e.keys()), 'pinning directive misplaced')
684
685 def test__produce_ns_desc_w_pinning(self):
686 nsd = self._get_ut_nsd_from_file('nsd_unittest3.yaml')
687 nsd = nsd['nsd']['nsd'][0]
688 pinning = [{'member-vnf-index': 'two', 'vimAccountId': '331ffdec-44a8-4707-94a1-af7a292d9735'}]
689 nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts),
690 self._produce_ut_vnf_price_list(),
691 nsd=nsd,
692 pil_info=None,
693 pinning=pinning)
694 ns_desc = nspdf._produce_ns_desc()
695 # check that all expected member-vnf-index are present
696 vnfs = [e['vnf_id'] for e in ns_desc]
697 self.assertEqual(Counter(['one', 'three', 'two']), Counter(vnfs), 'vnf_id invalid')
698
699 for e in ns_desc:
700 # check that vnf_price_per_vim has proper values
701 self.assertEqual(Counter([5, 10, 30, 30]), Counter(e['vnf_price_per_vim']), 'vnf_price_per_vim invalid')
702 # check that member-vnf-index 2 is pinned correctly
703 if e['vnf_id'] == 'two':
704 self.assertTrue('vim_account' in e.keys(), 'missing pinning directive')
705 self.assertTrue(pinning[0]['vimAccountId'] == e['vim_account'][3:].replace('_', '-'),
706 'invalid pinning vim-account')
707 else:
708 self.assertTrue('vim-account' not in e.keys(), 'pinning directive misplaced')
709
710 @mock.patch.object(NsPlacementDataFactory, '_produce_trp_link_characteristics_data')
711 @mock.patch.object(NsPlacementDataFactory, '_produce_vld_desc')
712 @mock.patch.object(NsPlacementDataFactory, '_produce_ns_desc')
713 def test_create_ns_placement_data_wo_order(self, mock_prd_ns_desc, mock_prd_vld_desc, mock_prd_trp_link_char):
714 """
715 :return:
716 """
717 vim_accounts_expected = [v.replace('-', '_') for v in ['vim92b056a7-38f5-438d-b8ee-3f93b3531f87',
718 'vim6618d412-d7fc-4eb0-a6f8-d2c258e0e900',
719 'vim331ffdec-44a8-4707-94a1-af7a292d9735',
720 'vimeda92f47-29b9-4007-9709-c1833dbfbe31']]
721
722 nsd = self._get_ut_nsd_from_file('nsd_unittest3.yaml')
723 nsd = nsd['nsd']['nsd'][0]
724 nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts),
725 self._produce_ut_vnf_price_list(),
726 nsd=nsd,
727 pil_info=self._populate_pil_info('pil_unittest1.yaml'),
728 pinning=None,
729 order_constraints=None)
730 nspd = nspdf.create_ns_placement_data()
731 self.assertEqual(Counter(vim_accounts_expected), Counter(nspd['vim_accounts']),
732 "vim_accounts incorrect")
733 # mock1.assert_called_once() Note for python > 3.5
734 self.assertTrue(mock_prd_ns_desc.called, '_produce_ns_desc not called')
735 # mock2.assert_called_once() Note for python > 3.5
736 self.assertTrue(mock_prd_vld_desc.called, ' _produce_vld_desc not called')
737 mock_prd_trp_link_char.assert_has_calls([call('pil_latency'), call('pil_jitter'), call('pil_price')])
738
739 regexps = [r"\{.*\}", r".*'file':.*mznplacement.py", r".*'time':.*datetime.datetime\(.*\)"]
740 generator_data = str(nspd['generator_data'])
741 for regex in regexps:
742 self.assertRegex(generator_data, regex, "generator data invalid")
743
744 @mock.patch.object(NsPlacementDataFactory, '_produce_trp_link_characteristics_data')
745 @mock.patch.object(NsPlacementDataFactory, '_produce_vld_desc')
746 @mock.patch.object(NsPlacementDataFactory, '_produce_ns_desc')
747 def test_create_ns_placement_data_w_order(self, mock_prd_ns_desc, mock_prd_vld_desc,
748 mock_prd_trp_link_char):
749 """
750 :return:
751 """
752 vim_accounts_expected = [v.replace('-', '_') for v in ['vim92b056a7-38f5-438d-b8ee-3f93b3531f87',
753 'vim6618d412-d7fc-4eb0-a6f8-d2c258e0e900',
754 'vim331ffdec-44a8-4707-94a1-af7a292d9735',
755 'vimeda92f47-29b9-4007-9709-c1833dbfbe31']]
756
757 nsd = self._get_ut_nsd_from_file('nsd_unittest3.yaml')
758 nsd = nsd['nsd']['nsd'][0]
759 nspdf = NsPlacementDataFactory(self._produce_ut_vim_accounts_info(TestNsPlacementDataFactory.vim_accounts),
760 self._produce_ut_vnf_price_list(),
761 nsd=nsd,
762 pil_info=self._populate_pil_info('pil_unittest1.yaml'),
763 pinning=None,
764 order_constraints={
765 'vld-constraints': [{'id': 'three_vnf_constrained_nsd_vld1',
766 'link-constraints': {'latency': 120,
767 'jitter': 21}},
768 {'id': 'three_vnf_constrained_nsd_vld2',
769 'link-constraints': {'latency': 121,
770 'jitter': 22}}]}
771 )
772 nspd = nspdf.create_ns_placement_data()
773 self.assertEqual(Counter(vim_accounts_expected), Counter(nspd['vim_accounts']),
774 "vim_accounts incorrect")
775 # mock1.assert_called_once() Note for python > 3.5
776 self.assertTrue(mock_prd_ns_desc.called, '_produce_ns_desc not called')
777 # mock2.assert_called_once() Note for python > 3.5
778 self.assertTrue(mock_prd_vld_desc.called, ' _produce_vld_desc not called')
779 mock_prd_trp_link_char.assert_has_calls([call('pil_latency'), call('pil_jitter'), call('pil_price')])
780
781 regexps = [r"\{.*\}", r".*'file':.*mznplacement.py", r".*'time':.*datetime.datetime\(.*\)"]
782 generator_data = str(nspd['generator_data'])
783 for regex in regexps:
784 self.assertRegex(generator_data, regex, "generator data invalid")
785
786
787 if __name__ == "__main__":
788 if __name__ == '__main__':
789 unittest.main()