blob: 2ad596d87b73f53c98b917b28376db356ed72715 [file] [log] [blame]
tierno1bfe4e22019-09-02 16:03:25 +00001#
2# Licensed under the Apache License, Version 2.0 (the "License"); you may
3# not use this file except in compliance with the License. You may obtain
4# a copy of the License at
5#
6# http://www.apache.org/licenses/LICENSE-2.0
7#
8# Unless required by applicable law or agreed to in writing, software
9# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11# License for the specific language governing permissions and limitations
12# under the License.
13#
14# For those usages not covered by the Apache License, Version 2.0 please
15# contact: esousa@whitestack.com or alfonso.tiernosepulveda@telefonica.com
16##
17
aticig544a2ae2022-04-05 09:00:17 +030018from contextlib import contextmanager
tierno1bfe4e22019-09-02 16:03:25 +000019import unittest
K Sai Kiran57589552021-01-27 21:38:34 +053020from time import time
21from unittest.mock import Mock, mock_open # patch, MagicMock
tierno1bfe4e22019-09-02 16:03:25 +000022from osm_common.dbbase import DbException
23from osm_nbi.engine import EngineException
24from osm_common.dbmemory import DbMemory
25from osm_common.fsbase import FsBase
26from osm_common.msgbase import MsgBase
beierlmcee2ebf2022-03-29 17:42:48 -040027from osm_common import dbbase
tierno1bfe4e22019-09-02 16:03:25 +000028from http import HTTPStatus
29from osm_nbi.instance_topics import NsLcmOpTopic, NsrTopic
garciadeblas4568a372021-03-24 09:19:48 +010030from osm_nbi.tests.test_db_descriptors import (
31 db_vim_accounts_text,
32 db_nsds_text,
33 db_vnfds_text,
34 db_nsrs_text,
35 db_vnfrs_text,
36)
tierno1bfe4e22019-09-02 16:03:25 +000037from copy import deepcopy
38import yaml
39
40
41class TestNsLcmOpTopic(unittest.TestCase):
tierno1bfe4e22019-09-02 16:03:25 +000042 def setUp(self):
43 self.db = DbMemory()
44 self.fs = Mock(FsBase())
45 self.fs.get_params.return_value = {"./fake/folder"}
46 self.fs.file_open = mock_open()
47 self.msg = Mock(MsgBase())
48 # create class
49 self.nslcmop_topic = NsLcmOpTopic(self.db, self.fs, self.msg, None)
50 self.nslcmop_topic.check_quota = Mock(return_value=None) # skip quota
51
garciadeblas4568a372021-03-24 09:19:48 +010052 self.db.create_list(
53 "vim_accounts", yaml.load(db_vim_accounts_text, Loader=yaml.Loader)
54 )
tierno1bfe4e22019-09-02 16:03:25 +000055 self.db.create_list("nsds", yaml.load(db_nsds_text, Loader=yaml.Loader))
56 self.db.create_list("vnfds", yaml.load(db_vnfds_text, Loader=yaml.Loader))
57 self.db.create_list("vnfrs", yaml.load(db_vnfrs_text, Loader=yaml.Loader))
58 self.db.create_list("nsrs", yaml.load(db_nsrs_text, Loader=yaml.Loader))
59 self.db.create = Mock(return_value="created_id")
tierno1bfe4e22019-09-02 16:03:25 +000060 self.nsd = self.db.get_list("nsds")[0]
61 self.nsd_id = self.nsd["_id"]
62 self.nsr = self.db.get_list("nsrs")[0]
63 self.nsr_id = self.nsr["_id"]
64 self.nsr_project = self.nsr["_admin"]["projects_read"][0]
65
66 self.vim = self.db.get_list("vim_accounts")[0]
67 self.vim_id = self.vim["_id"]
68
69 def test_create_instantiate(self):
elumalai6380e7c2022-04-28 00:15:59 +053070 self.db.set_one = Mock(return_value={"updated": 1})
garciadeblas4568a372021-03-24 09:19:48 +010071 session = {
72 "force": False,
73 "admin": False,
74 "public": False,
75 "project_id": [self.nsr_project],
76 "method": "write",
77 }
tierno1bfe4e22019-09-02 16:03:25 +000078 indata = {
79 "nsdId": self.nsd_id,
80 "nsInstanceId": self.nsr_id,
81 "nsName": "name",
82 "vimAccountId": self.vim_id,
garciadeblas4568a372021-03-24 09:19:48 +010083 "additionalParamsForVnf": [
84 {
85 "member-vnf-index": "1",
86 "additionalParams": {"touch_filename": "file"},
87 },
88 {
89 "member-vnf-index": "2",
90 "additionalParams": {"touch_filename": "file"},
91 },
92 ],
93 "vnf": [
94 {
95 "member-vnf-index": "1",
96 "vdu": [
97 {
98 "id": "dataVM",
99 "interface": [
100 {
101 "name": "dataVM-eth0",
102 "ip-address": "10.11.12.13",
103 "floating-ip-required": True,
104 }
105 ],
106 }
107 ],
108 "internal-vld": [
109 {"name": "internal", "vim-network-id": "vim-net-id"}
110 ],
111 }
112 ],
tierno1bfe4e22019-09-02 16:03:25 +0000113 "lcmOperationType": "instantiate",
tierno1bfe4e22019-09-02 16:03:25 +0000114 }
115 rollback = []
116 headers = {}
117
garciadeblas4568a372021-03-24 09:19:48 +0100118 nslcmop_id, _ = self.nslcmop_topic.new(
119 rollback, session, indata=deepcopy(indata), kwargs=None, headers=headers
120 )
tierno1bfe4e22019-09-02 16:03:25 +0000121
122 # check nslcmop is created at database
garciadeblas4568a372021-03-24 09:19:48 +0100123 self.assertEqual(
124 self.db.create.call_count,
125 1,
126 "database create not called, or called more than once",
127 )
tierno1bfe4e22019-09-02 16:03:25 +0000128 _call = self.db.create.call_args_list[0]
garciadeblas4568a372021-03-24 09:19:48 +0100129 self.assertEqual(
130 _call[0][0], "nslcmops", "must be create a nslcmops entry at database"
131 )
tierno1bfe4e22019-09-02 16:03:25 +0000132
133 created_nslcmop = _call[0][1]
garciadeblas4568a372021-03-24 09:19:48 +0100134 self.assertEqual(
135 nslcmop_id,
136 created_nslcmop["_id"],
137 "mismatch between return id and database '_id'",
138 )
139 self.assertEqual(
140 self.nsr_id,
141 created_nslcmop["nsInstanceId"],
142 "bad reference id from nslcmop to nsr",
143 )
144 self.assertTrue(
145 created_nslcmop["_admin"].get("projects_read"),
146 "Database record must contain '_amdin.projects_read'",
147 )
148 self.assertIn(
149 "created",
150 created_nslcmop["_admin"],
151 "Database record must contain '_admin.created'",
152 )
153 self.assertTrue(
154 created_nslcmop["lcmOperationType"] == "instantiate",
155 "Database record must contain 'lcmOperationType=instantiate'",
156 )
tierno1bfe4e22019-09-02 16:03:25 +0000157
garciadeblas4568a372021-03-24 09:19:48 +0100158 self.assertEqual(
159 len(rollback),
160 len(self.db.set_one.call_args_list) + 1,
161 "rollback mismatch with created/set items at database",
162 )
tierno1bfe4e22019-09-02 16:03:25 +0000163
164 # test parameters with error
165 bad_id = "88d90b0c-faff-4b9f-bccd-aaaaaaaaaaaa"
166 test_set = (
garciadeblas4568a372021-03-24 09:19:48 +0100167 (
168 "nsr not found",
169 {"nsInstanceId": bad_id},
170 DbException,
171 HTTPStatus.NOT_FOUND,
172 ("not found", bad_id),
173 ),
tierno1bfe4e22019-09-02 16:03:25 +0000174 # TODO add "nsd"
175 # ({"vimAccountId": bad_id}, DbException, HTTPStatus.NOT_FOUND, ("not found", bad_id)), # TODO add "vim"
garciadeblas4568a372021-03-24 09:19:48 +0100176 (
177 "bad member-vnf-index",
178 {"vnf.0.member-vnf-index": "k"},
179 EngineException,
180 HTTPStatus.BAD_REQUEST,
181 ("k",),
182 ),
tierno1bfe4e22019-09-02 16:03:25 +0000183 )
184 for message, kwargs_, expect_exc, expect_code, expect_text_list in test_set:
185 with self.assertRaises(expect_exc, msg=message) as e:
garciadeblas4568a372021-03-24 09:19:48 +0100186 self.nslcmop_topic.new(
187 rollback,
188 session,
189 indata=deepcopy(indata),
190 kwargs=kwargs_,
191 headers=headers,
192 )
tierno1bfe4e22019-09-02 16:03:25 +0000193 if expect_code:
194 self.assertTrue(e.exception.http_code == expect_code)
195 if expect_text_list:
196 for expect_text in expect_text_list:
garciadeblas4568a372021-03-24 09:19:48 +0100197 self.assertIn(
198 expect_text,
199 str(e.exception).lower(),
200 "Expected '{}' at exception text".format(expect_text),
201 )
tierno1bfe4e22019-09-02 16:03:25 +0000202
203 def test_check_ns_operation_action(self):
204 nsrs = self.db.get_list("nsrs")[0]
205 session = {}
206
207 indata = {
208 "member_vnf_index": "1",
209 "vdu_id": None,
210 "primitive": "touch",
garciadeblas4568a372021-03-24 09:19:48 +0100211 "primitive_params": {"filename": "file"},
tierno1bfe4e22019-09-02 16:03:25 +0000212 }
213
214 self.nslcmop_topic._check_ns_operation(session, nsrs, "action", indata)
215 for k in indata:
216 indata_copy = indata.copy()
217 if k == "primitive_params":
218 continue
219 indata_copy[k] = "non_existing"
220 with self.assertRaises(EngineException) as exc_manager:
garciadeblas4568a372021-03-24 09:19:48 +0100221 self.nslcmop_topic._check_ns_operation(
222 session, nsrs, "action", indata_copy
223 )
tierno1bfe4e22019-09-02 16:03:25 +0000224 exc = exc_manager.exception
garciadeblas4568a372021-03-24 09:19:48 +0100225 self.assertEqual(
226 exc.http_code,
227 HTTPStatus.BAD_REQUEST,
228 "Engine exception bad http_code with {}".format(indata_copy),
229 )
tierno1bfe4e22019-09-02 16:03:25 +0000230
elumalai6380e7c2022-04-28 00:15:59 +0530231 def test_update_remove_vnf(self):
232 vnfr_id = self.db.get_list("vnfrs")[0]["_id"]
233 session = {}
234 self.db.set_one(
235 "nsrs",
236 {"_id": self.nsr_id},
237 {"_admin.nsState": "INSTANTIATED"},
238 )
239 indata = {
240 "lcmOperationType": "update",
241 "updateType": "REMOVE_VNF",
242 "nsInstanceId": self.nsr_id,
243 "removeVnfInstanceId": vnfr_id
244 }
245
246 session = {
247 "force": False,
248 "admin": False,
249 "public": False,
250 "project_id": [self.nsr_project],
251 "method": "write",
252 }
253 rollback = []
254 headers = {}
255
256 nslcmop_id, _ = self.nslcmop_topic.new(
257 rollback, session, indata, kwargs=None, headers=headers
258 )
259
260 self.assertEqual(
261 self.db.create.call_count,
262 1,
263 "database create not called, or called more than once",
264 )
265 _call = self.db.create.call_args_list[0]
266 self.assertEqual(
267 _call[0][0], "nslcmops", "nslcmops entry must be created at database"
268 )
269 created_nslcmop = _call[0][1]
270 self.assertEqual(
271 self.nsr_id,
272 created_nslcmop["nsInstanceId"],
273 "mismatch between nsId '_id' in created nslcmop and database nsr",
274 )
275 self.assertTrue(
276 created_nslcmop["lcmOperationType"] == "update",
277 "Database record must contain 'lcmOperationType=update'",
278 )
279 self.assertTrue(
280 created_nslcmop["operationParams"]["updateType"] == "REMOVE_VNF",
281 "Database record must contain 'updateType=REMOVE_VNF'",
282 )
283
tierno1bfe4e22019-09-02 16:03:25 +0000284
beierlmcee2ebf2022-03-29 17:42:48 -0400285class TestNsLcmOpTopicWithMock(unittest.TestCase):
286 def setUp(self):
287 self.db = Mock(dbbase.DbBase())
288 self.fs = Mock(FsBase())
289 self.fs.get_params.return_value = {"./fake/folder"}
290 self.fs.file_open = mock_open()
291 self.msg = Mock(MsgBase())
292 # create class
293 self.nslcmop_topic = NsLcmOpTopic(self.db, self.fs, self.msg, None)
294
295 def test_get_vnfd_from_vnf_member_revision(self):
296 test_vnfr = yaml.load(db_vnfrs_text, Loader=yaml.Loader)[0]
297 test_vnfd = yaml.load(db_vnfds_text, Loader=yaml.Loader)
298 self.db.get_one.side_effect = [test_vnfr, test_vnfd]
299 vnfr = self.nslcmop_topic._get_vnfd_from_vnf_member_index("1", test_vnfr['_id'])
300 self.assertEqual(self.db.get_one.call_args_list[0][0][0], 'vnfrs', "Incorrect first DB lookup")
301 self.assertEqual(self.db.get_one.call_args_list[1][0][0], 'vnfds', "Incorrect second DB lookup")
302
303 def test_get_vnfd_from_vnf_member_no_revision(self):
304 test_vnfr = yaml.load(db_vnfrs_text, Loader=yaml.Loader)[0]
305 test_vnfr['revision'] = 3
306 test_vnfd = yaml.load(db_vnfds_text, Loader=yaml.Loader)
307 self.db.get_one.side_effect = [test_vnfr, test_vnfd]
308 vnfr = self.nslcmop_topic._get_vnfd_from_vnf_member_index("1", test_vnfr['_id'])
309 self.assertEqual(self.db.get_one.call_args_list[0][0][0], 'vnfrs', "Incorrect first DB lookup")
310 self.assertEqual(self.db.get_one.call_args_list[1][0][0], 'vnfds_revisions', "Incorrect second DB lookup")
311
aticig544a2ae2022-04-05 09:00:17 +0300312 @contextmanager
313 def assertNotRaises(self, exception_type):
314 try:
315 yield None
316 except exception_type:
317 raise self.failureException("{} raised".format(exception_type.__name__))
318
319 def test_check_ns_update_operation(self):
320 self.db = DbMemory()
321 self.nslcmop_topic = NsLcmOpTopic(self.db, self.fs, self.msg, None)
322 session = {}
323
324 with self.subTest(i=1, t="VNF instance does not belong to NS"):
325 test_vnfr = yaml.load(db_vnfrs_text, Loader=yaml.Loader)
326 test_vnfr[0]["revision"] = 2
327 test_nsr = yaml.load(db_nsrs_text, Loader=yaml.Loader)
328 test_nsr[0]["constituent-vnfr-ref"][
329 0
330 ] = "99d90b0c-faff-4b9f-bccd-017f33985984"
331 self.db.create_list("vnfrs", test_vnfr)
332 self.db.create_list("nsrs", test_nsr)
333 nsrs = self.db.get_list("nsrs")[0]
334 indata = {
335 "updateType": "CHANGE_VNFPKG",
336 "changeVnfPackageData": {
337 "vnfInstanceId": "88d90b0c-faff-4b9f-bccd-017f33985984",
338 "vnfdId": "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77",
339 },
340 "nsInstanceId": "f48163a6-c807-47bc-9682-f72caef5af85",
341 }
342 with self.assertRaises(EngineException) as expected_exception:
343 self.nslcmop_topic._check_ns_operation(session, nsrs, "update", indata)
344 self.assertEqual(
345 str(expected_exception.exception),
346 "Error in validating ns-update request: vnf 88d90b0c-faff-4b9f-bccd-017f33985984"
347 " does not belong to NS f48163a6-c807-47bc-9682-f72caef5af85",
348 )
349
350 with self.subTest(i=2, t="Ns update request validated with no exception"):
351 test_vnfr = yaml.load(db_vnfrs_text, Loader=yaml.Loader)
352 test_vnfr[0]["revision"] = 2
353 test_nsr = yaml.load(db_nsrs_text, Loader=yaml.Loader)
354 self.db.create_list("vnfrs", test_vnfr)
355 self.db.create_list("nsrs", test_nsr)
356 nsrs = self.db.get_list("nsrs")[1]
357 indata = {
358 "updateType": "CHANGE_VNFPKG",
359 "changeVnfPackageData": {
360 "vnfInstanceId": "88d90b0c-faff-4b9f-bccd-017f33985984",
361 "vnfdId": "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77",
362 },
363 "nsInstanceId": "f48163a6-c807-47bc-9682-f72caef5af85",
364 }
365 with self.assertNotRaises(EngineException):
366 self.nslcmop_topic._check_ns_operation(session, nsrs, "update", indata)
367
368 with self.subTest(
369 i=3, t="Ns update request rejected because of too small timeout"
370 ):
371 indata = {
372 "updateType": "CHANGE_VNFPKG",
373 "changeVnfPackageData": {
374 "vnfInstanceId": "88d90b0c-faff-4b9f-bccd-017f33985984",
375 "vnfdId": "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77",
376 },
377 "nsInstanceId": "f48163a6-c807-47bc-9682-f72caef5af85",
378 "timeout_ns_update": 50,
379 }
380 with self.assertRaises(EngineException) as expected_exception:
381 self.nslcmop_topic._check_ns_operation(session, nsrs, "update", indata)
382 self.assertEqual(
383 str(expected_exception.exception),
384 "Error in validating ns-update request: 50 second is not enough "
385 "to upgrade the VNF instance: 88d90b0c-faff-4b9f-bccd-017f33985984",
386 )
387
388 with self.subTest(i=4, t="wrong vnfdid is given as an update parameter"):
389 test_vnfr = yaml.load(db_vnfrs_text, Loader=yaml.Loader)
390 test_vnfr[0]["revision"] = 2
391 test_nsr = yaml.load(db_nsrs_text, Loader=yaml.Loader)
392 self.db.create_list("vnfrs", test_vnfr)
393 self.db.create_list("nsrs", test_nsr)
394 nsrs = self.db.get_list("nsrs")[2]
395 indata = {
396 "updateType": "CHANGE_VNFPKG",
397 "changeVnfPackageData": {
398 "vnfInstanceId": "88d90b0c-faff-4b9f-bccd-017f33985984",
399 "vnfdId": "9637bcf8-cf14-42dc-ad70-c66fcf1e6e77",
400 },
401 "nsInstanceId": "f48163a6-c807-47bc-9682-f72caef5af85",
402 }
403 with self.assertRaises(EngineException) as expected_exception:
404 self.nslcmop_topic._check_ns_operation(session, nsrs, "update", indata)
405 self.assertEqual(
406 str(expected_exception.exception),
407 "Error in validating ns-update request: vnfd-id 9637bcf8-cf14-42dc-ad70-c66fcf1e6e77 does not "
408 "match with the vnfd-id: 7637bcf8-cf14-42dc-ad70-c66fcf1e6e77 of "
409 "VNF instance: 88d90b0c-faff-4b9f-bccd-017f33985984",
410 )
411
elumalai6380e7c2022-04-28 00:15:59 +0530412 with self.subTest(i=5, t="Ns update REMOVE_VNF request validated with no exception"):
413 test_vnfr = yaml.load(db_vnfrs_text, Loader=yaml.Loader)
414 test_vnfr[0]["revision"] = 2
415 test_nsr = yaml.load(db_nsrs_text, Loader=yaml.Loader)
416 self.db.create_list("vnfrs", test_vnfr)
417 self.db.create_list("nsrs", test_nsr)
418 nsrs = self.db.get_list("nsrs")[1]
419 indata = {
420 "updateType": "REMOVE_VNF",
421 "removeVnfInstanceId": "88d90b0c-faff-4b9f-bccd-017f33985984",
422 "nsInstanceId": "f48163a6-c807-47bc-9682-f72caef5af85",
423 }
424 with self.assertNotRaises(EngineException):
425 self.nslcmop_topic._check_ns_operation(session, nsrs, "update", indata)
beierlmcee2ebf2022-03-29 17:42:48 -0400426
tierno1bfe4e22019-09-02 16:03:25 +0000427class TestNsrTopic(unittest.TestCase):
tierno1bfe4e22019-09-02 16:03:25 +0000428 def setUp(self):
429 self.db = DbMemory()
430 self.fs = Mock(FsBase())
431 self.fs.get_params.return_value = {"./fake/folder"}
432 self.fs.file_open = mock_open()
433 self.msg = Mock(MsgBase())
434 # create class
435 self.nsr_topic = NsrTopic(self.db, self.fs, self.msg, None)
436 self.nsr_topic.check_quota = Mock(return_value=None) # skip quota
437
garciadeblas4568a372021-03-24 09:19:48 +0100438 self.db.create_list(
439 "vim_accounts", yaml.load(db_vim_accounts_text, Loader=yaml.Loader)
440 )
tierno1bfe4e22019-09-02 16:03:25 +0000441 self.db.create_list("nsds", yaml.load(db_nsds_text, Loader=yaml.Loader))
442 self.db.create_list("vnfds", yaml.load(db_vnfds_text, Loader=yaml.Loader))
443 self.db.create = Mock(return_value="created_id")
444 self.nsd = self.db.get_list("nsds")[0]
445 self.nsd_id = self.nsd["_id"]
446 self.nsd_project = self.nsd["_admin"]["projects_read"][0]
447
448 self.vim = self.db.get_list("vim_accounts")[0]
449 self.vim_id = self.vim["_id"]
450
451 def test_create(self):
garciadeblas4568a372021-03-24 09:19:48 +0100452 session = {
453 "force": False,
454 "admin": False,
455 "public": False,
456 "project_id": [self.nsd_project],
457 "method": "write",
458 }
tierno1bfe4e22019-09-02 16:03:25 +0000459 indata = {
460 "nsdId": self.nsd_id,
461 "nsName": "name",
462 "vimAccountId": self.vim_id,
garciaale7cbd03c2020-11-27 10:38:35 -0300463 "additionalParamsForVnf": [
garciadeblas4568a372021-03-24 09:19:48 +0100464 {
465 "member-vnf-index": "hackfest_vnf1",
466 "additionalParams": {"touch_filename": "file"},
467 },
468 {
469 "member-vnf-index": "hackfest_vnf2",
470 "additionalParams": {"touch_filename": "file"},
471 },
472 ],
tierno1bfe4e22019-09-02 16:03:25 +0000473 }
474 rollback = []
475 headers = {}
476
garciadeblas4568a372021-03-24 09:19:48 +0100477 self.nsr_topic.new(
478 rollback, session, indata=indata, kwargs=None, headers=headers
479 )
tierno1bfe4e22019-09-02 16:03:25 +0000480
481 # check vnfrs and nsrs created in whatever order
482 created_vnfrs = []
483 created_nsrs = []
484 nsr_id = None
485 for _call in self.db.create.call_args_list:
486 assert len(_call[0]) >= 2, "called db.create with few parameters"
487 created_item = _call[0][1]
488 if _call[0][0] == "vnfrs":
489 created_vnfrs.append(created_item)
garciadeblas4568a372021-03-24 09:19:48 +0100490 self.assertIn(
491 "member-vnf-index-ref",
492 created_item,
493 "Created item must contain member-vnf-index-ref section",
494 )
tierno1bfe4e22019-09-02 16:03:25 +0000495 if nsr_id:
garciadeblas4568a372021-03-24 09:19:48 +0100496 self.assertEqual(
497 nsr_id,
498 created_item["nsr-id-ref"],
499 "bad reference id from vnfr to nsr",
500 )
tierno1bfe4e22019-09-02 16:03:25 +0000501 else:
502 nsr_id = created_item["nsr-id-ref"]
503
504 elif _call[0][0] == "nsrs":
505 created_nsrs.append(created_item)
506 if nsr_id:
garciadeblas4568a372021-03-24 09:19:48 +0100507 self.assertEqual(
508 nsr_id, created_item["_id"], "bad reference id from vnfr to nsr"
509 )
tierno1bfe4e22019-09-02 16:03:25 +0000510 else:
511 nsr_id = created_item["_id"]
512 else:
garciadeblas4568a372021-03-24 09:19:48 +0100513 assert True, "created an unknown record {} at database".format(
514 _call[0][0]
515 )
tierno1bfe4e22019-09-02 16:03:25 +0000516
garciadeblas4568a372021-03-24 09:19:48 +0100517 self.assertTrue(
518 created_item["_admin"].get("projects_read"),
519 "Database record must contain '_amdin.projects_read'",
520 )
521 self.assertIn(
522 "created",
523 created_item["_admin"],
524 "Database record must contain '_admin.created'",
525 )
526 self.assertTrue(
527 created_item["_admin"]["nsState"] == "NOT_INSTANTIATED",
528 "Database record must contain '_admin.nstate=NOT INSTANTIATE'",
529 )
tierno1bfe4e22019-09-02 16:03:25 +0000530
garciadeblas4568a372021-03-24 09:19:48 +0100531 self.assertEqual(
532 len(created_vnfrs), 2, "created a mismatch number of vnfr at database"
533 )
aticigc9c03392022-06-16 01:39:44 +0300534
535 self.assertEqual(
536 created_vnfrs[0]["vdur"][0]["interfaces"][0]["position"],
537 1,
538 "vdur first interface position does not match",
539 )
540
541 self.assertEqual(
542 created_vnfrs[0]["vdur"][0]["interfaces"][1]["position"],
543 2,
544 "vdur second interface position does not match",
545 )
546
garciadeblas4568a372021-03-24 09:19:48 +0100547 self.assertEqual(
548 len(created_nsrs), 1, "Only one nsrs must be created at database"
549 )
550 self.assertEqual(
551 len(rollback),
552 len(created_vnfrs) + 1,
553 "rollback mismatch with created items at database",
554 )
tierno1bfe4e22019-09-02 16:03:25 +0000555
556 # test parameters with error
557 bad_id = "88d90b0c-faff-4b9f-bccd-aaaaaaaaaaaa"
558 test_set = (
559 # TODO add "nsd"
garciadeblas4568a372021-03-24 09:19:48 +0100560 (
561 "nsd not found",
562 {"nsdId": bad_id},
563 DbException,
564 HTTPStatus.NOT_FOUND,
565 ("not found", bad_id),
566 ),
tierno1bfe4e22019-09-02 16:03:25 +0000567 # ({"vimAccountId": bad_id}, DbException, HTTPStatus.NOT_FOUND, ("not found", bad_id)), # TODO add "vim"
garciadeblas4568a372021-03-24 09:19:48 +0100568 (
569 "additional params not supply",
570 {"additionalParamsForVnf.0.member-vnf-index": "k"},
571 EngineException,
572 HTTPStatus.BAD_REQUEST,
573 None,
574 ),
tierno1bfe4e22019-09-02 16:03:25 +0000575 )
576 for message, kwargs_, expect_exc, expect_code, expect_text_list in test_set:
577 with self.assertRaises(expect_exc, msg=message) as e:
garciadeblas4568a372021-03-24 09:19:48 +0100578 self.nsr_topic.new(
579 rollback,
580 session,
581 indata=deepcopy(indata),
582 kwargs=kwargs_,
583 headers=headers,
584 )
tierno1bfe4e22019-09-02 16:03:25 +0000585 if expect_code:
586 self.assertTrue(e.exception.http_code == expect_code)
587 if expect_text_list:
588 for expect_text in expect_text_list:
K Sai Kiran57589552021-01-27 21:38:34 +0530589 self.assertIn(expect_text, str(e.exception).lower(),
590 "Expected '{}' at exception text".format(expect_text))
591
592 def test_show_instance(self):
593 session = {"force": False, "admin": False, "public": False, "project_id": [self.nsd_project], "method": "write"}
594 filter_q = {}
595 for refresh_status in ("true", "false"):
596 self.db.create_list("nsrs", yaml.load(db_nsrs_text, Loader=yaml.Loader))
597 actual_nsr = self.db.get_list("nsrs")[0]
598 nsr_id = actual_nsr["_id"]
599 filter_q['vcaStatus-refresh'] = refresh_status
600 expected_nsr = self.nsr_topic.show(session, nsr_id, filter_q=filter_q)
601 self.nsr_topic.delete(session, nsr_id)
602 actual_nsr.pop("_admin")
603 expected_nsr.pop("_admin")
604 self.assertEqual(expected_nsr, actual_nsr, "Database nsr and show() nsr do not match.")
605
606 def test_vca_status_refresh(self):
607 session = {"force": False, "admin": False, "public": False, "project_id": [self.nsd_project], "method": "write"}
608 filter_q = {'vcaStatus-refresh': 'true'}
609 time_delta = 120
610 self.db.create_list("nsrs", yaml.load(db_nsrs_text, Loader=yaml.Loader))
611 nsr = self.db.get_list("nsrs")[0]
612
613 # When vcaStatus-refresh is true
614 filter_q['vcaStatus-refresh'] = "true"
615 self.nsr_topic.vca_status_refresh(session, nsr, filter_q)
616 msg_args = self.msg.write.call_args[0]
617 self.assertEqual(msg_args[1], "vca_status_refresh", "Wrong message action")
618 self.assertGreater(nsr["_admin"]["modified"], time() - time_delta)
619
620 # When vcaStatus-refresh is false but modified time is within threshold
621 filter_q['vcaStatus-refresh'] = "false"
622 time_now = time()
623 nsr["_admin"]["modified"] = time_now
624 self.nsr_topic.vca_status_refresh(session, nsr, filter_q)
625 msg_args = self.msg.write.call_args[1]
626 self.assertEqual(msg_args, {}, "Message should not be sent.")
627 self.assertEqual(nsr["_admin"]["modified"], time_now, "Modified time should not be changed.")
628
629 # When vcaStatus-refresh is false but modified time is less than threshold
630 filter_q['vcaStatus-refresh'] = "false"
631 nsr["_admin"]["modified"] = time() - (2*time_delta)
632 self.nsr_topic.vca_status_refresh(session, nsr, filter_q)
633 msg_args = self.msg.write.call_args[0]
634 self.assertEqual(msg_args[1], "vca_status_refresh", "Wrong message action")
635 self.nsr_topic.delete(session, nsr["_id"])
636 self.assertGreater(nsr["_admin"]["modified"], time() - time_delta, "Modified time is not changed.")
tiernof5f2e3f2020-03-23 14:42:10 +0000637
638 def test_delete_ns(self):
639 self.db.create_list("nsrs", yaml.load(db_nsrs_text, Loader=yaml.Loader))
640 self.nsr = self.db.get_list("nsrs")[0]
641 self.nsr_id = self.nsr["_id"]
642 self.db_set_one = self.db.set_one
643 p_id = self.nsd_project
644 p_other = "other_p"
645
garciadeblas4568a372021-03-24 09:19:48 +0100646 session = {
647 "force": False,
648 "admin": False,
649 "public": None,
650 "project_id": [p_id],
651 "method": "delete",
652 }
653 session2 = {
654 "force": False,
655 "admin": False,
656 "public": None,
657 "project_id": [p_other],
658 "method": "delete",
659 }
660 session_force = {
661 "force": True,
662 "admin": True,
663 "public": None,
664 "project_id": [],
665 "method": "delete",
666 }
667 with self.subTest(i=1, t="Normal Deletion"):
tiernof5f2e3f2020-03-23 14:42:10 +0000668 self.db.del_one = Mock()
669 self.db.set_one = Mock()
670 self.nsr_topic.delete(session, self.nsr_id)
671
tiernof0441ea2020-05-26 15:39:18 +0000672 db_args_ro_nsrs = self.db.del_one.call_args_list[1][0]
673 db_args = self.db.del_one.call_args_list[0][0]
tiernof5f2e3f2020-03-23 14:42:10 +0000674 msg_args = self.msg.write.call_args[0]
garciadeblas4568a372021-03-24 09:19:48 +0100675 self.assertEqual(
676 msg_args[0], self.nsr_topic.topic_msg, "Wrong message topic"
677 )
tiernof5f2e3f2020-03-23 14:42:10 +0000678 self.assertEqual(msg_args[1], "deleted", "Wrong message action")
679 self.assertEqual(msg_args[2], {"_id": self.nsr_id}, "Wrong message content")
tiernof0441ea2020-05-26 15:39:18 +0000680 self.assertEqual(db_args_ro_nsrs[0], "ro_nsrs", "Wrong DB topic")
tiernof5f2e3f2020-03-23 14:42:10 +0000681 self.assertEqual(db_args[0], self.nsr_topic.topic, "Wrong DB topic")
682 self.assertEqual(db_args[1]["_id"], self.nsr_id, "Wrong DB ID")
garciadeblas4568a372021-03-24 09:19:48 +0100683 self.assertEqual(
684 db_args[1]["_admin.projects_read.cont"], [p_id], "Wrong DB filter"
685 )
tiernof5f2e3f2020-03-23 14:42:10 +0000686 self.db.set_one.assert_not_called()
687 fs_del_calls = self.fs.file_delete.call_args_list
688 self.assertEqual(fs_del_calls[0][0][0], self.nsr_id, "Wrong FS file id")
garciadeblas4568a372021-03-24 09:19:48 +0100689 with self.subTest(i=2, t="No delete because referenced by other project"):
690 self.db_set_one(
691 "nsrs",
692 {"_id": self.nsr_id},
693 update_dict=None,
694 push={
695 "_admin.projects_read": p_other,
696 "_admin.projects_write": p_other,
697 },
698 )
tiernof5f2e3f2020-03-23 14:42:10 +0000699 self.db.del_one.reset_mock()
700 self.db.set_one.reset_mock()
701 self.msg.write.reset_mock()
702 self.fs.file_delete.reset_mock()
703
704 self.nsr_topic.delete(session2, self.nsr_id)
705 self.db.del_one.assert_not_called()
706 self.msg.write.assert_not_called()
707 db_s1_args = self.db.set_one.call_args
708 self.assertEqual(db_s1_args[0][0], self.nsr_topic.topic, "Wrong DB topic")
709 self.assertEqual(db_s1_args[0][1]["_id"], self.nsr_id, "Wrong DB ID")
garciadeblas4568a372021-03-24 09:19:48 +0100710 self.assertIsNone(
711 db_s1_args[1]["update_dict"], "Wrong DB update dictionary"
712 )
713 self.assertEqual(
714 db_s1_args[1]["pull_list"],
715 {"_admin.projects_read": [p_other], "_admin.projects_write": [p_other]},
716 "Wrong DB pull_list dictionary",
717 )
tiernof5f2e3f2020-03-23 14:42:10 +0000718 self.fs.file_delete.assert_not_called()
garciadeblas4568a372021-03-24 09:19:48 +0100719 with self.subTest(i=4, t="Delete with force and admin"):
tiernof5f2e3f2020-03-23 14:42:10 +0000720 self.db.del_one.reset_mock()
721 self.db.set_one.reset_mock()
722 self.msg.write.reset_mock()
723 self.fs.file_delete.reset_mock()
724 self.nsr_topic.delete(session_force, self.nsr_id)
725
tiernof0441ea2020-05-26 15:39:18 +0000726 db_args_ro_nsrs = self.db.del_one.call_args_list[1][0]
727 db_args = self.db.del_one.call_args_list[0][0]
tiernof5f2e3f2020-03-23 14:42:10 +0000728 msg_args = self.msg.write.call_args[0]
garciadeblas4568a372021-03-24 09:19:48 +0100729 self.assertEqual(
730 msg_args[0], self.nsr_topic.topic_msg, "Wrong message topic"
731 )
tiernof5f2e3f2020-03-23 14:42:10 +0000732 self.assertEqual(msg_args[1], "deleted", "Wrong message action")
733 self.assertEqual(msg_args[2], {"_id": self.nsr_id}, "Wrong message content")
tiernof0441ea2020-05-26 15:39:18 +0000734 self.assertEqual(db_args_ro_nsrs[0], "ro_nsrs", "Wrong DB topic")
tiernof5f2e3f2020-03-23 14:42:10 +0000735 self.assertEqual(db_args[0], self.nsr_topic.topic, "Wrong DB topic")
736 self.assertEqual(db_args[1]["_id"], self.nsr_id, "Wrong DB ID")
737 self.db.set_one.assert_not_called()
738 fs_del_calls = self.fs.file_delete.call_args_list
739 self.assertEqual(fs_del_calls[0][0][0], self.nsr_id, "Wrong FS file id")
garciadeblas4568a372021-03-24 09:19:48 +0100740 with self.subTest(i=3, t="Conflict on Delete - NS in INSTANTIATED state"):
741 self.db_set_one(
742 "nsrs",
743 {"_id": self.nsr_id},
744 {"_admin.nsState": "INSTANTIATED"},
745 pull={
746 "_admin.projects_read": p_other,
747 "_admin.projects_write": p_other,
748 },
749 )
tiernof5f2e3f2020-03-23 14:42:10 +0000750 self.db.del_one.reset_mock()
751 self.db.set_one.reset_mock()
752 self.msg.write.reset_mock()
753 self.fs.file_delete.reset_mock()
754
garciadeblas4568a372021-03-24 09:19:48 +0100755 with self.assertRaises(
756 EngineException, msg="Accepted NSR with nsState INSTANTIATED"
757 ) as e:
tiernof5f2e3f2020-03-23 14:42:10 +0000758 self.nsr_topic.delete(session, self.nsr_id)
garciadeblas4568a372021-03-24 09:19:48 +0100759 self.assertEqual(
760 e.exception.http_code, HTTPStatus.CONFLICT, "Wrong HTTP status code"
761 )
tiernof5f2e3f2020-03-23 14:42:10 +0000762 self.assertIn("INSTANTIATED", str(e.exception), "Wrong exception text")
763 # TODOD with self.subTest(i=3, t='Conflict on Delete - NS in use by NSI'):
764
garciadeblas4568a372021-03-24 09:19:48 +0100765 with self.subTest(i=4, t="Non-existent NS"):
tiernof5f2e3f2020-03-23 14:42:10 +0000766 self.db.del_one.reset_mock()
767 self.db.set_one.reset_mock()
768 self.msg.write.reset_mock()
769 self.fs.file_delete.reset_mock()
770 excp_msg = "Not found"
garciadeblas4568a372021-03-24 09:19:48 +0100771 with self.assertRaises(
772 DbException, msg="Accepted non-existent NSD ID"
773 ) as e:
tiernof5f2e3f2020-03-23 14:42:10 +0000774 self.nsr_topic.delete(session2, "other_id")
garciadeblas4568a372021-03-24 09:19:48 +0100775 self.assertEqual(
776 e.exception.http_code, HTTPStatus.NOT_FOUND, "Wrong HTTP status code"
777 )
tiernof5f2e3f2020-03-23 14:42:10 +0000778 self.assertIn(excp_msg, str(e.exception), "Wrong exception text")
779 self.assertIn("other_id", str(e.exception), "Wrong exception text")
780 return