Code Coverage

Cobertura Coverage Report > osm_nbi.tests >

test_instance_topics.py

Trend

File Coverage summary

NameClassesLinesConditionals
test_instance_topics.py
100%
1/1
99%
381/385
100%
0/0

Coverage Breakdown by Class

NameLinesConditionals
test_instance_topics.py
99%
381/385
N/A

Source

osm_nbi/tests/test_instance_topics.py
1 #
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
18 1 from contextlib import contextmanager
19 1 import unittest
20 1 from time import time
21 1 from unittest.mock import Mock, mock_open  # patch, MagicMock
22 1 from osm_common.dbbase import DbException
23 1 from osm_nbi.engine import EngineException
24 1 from osm_common.dbmemory import DbMemory
25 1 from osm_common.fsbase import FsBase
26 1 from osm_common.msgbase import MsgBase
27 1 from osm_common import dbbase
28 1 from http import HTTPStatus
29 1 from osm_nbi.instance_topics import NsLcmOpTopic, NsrTopic
30 1 from 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 )
37 1 from copy import deepcopy
38 1 import yaml
39
40
41 1 class TestNsLcmOpTopic(unittest.TestCase):
42 1     def setUp(self):
43 1         self.db = DbMemory()
44 1         self.fs = Mock(FsBase())
45 1         self.fs.get_params.return_value = {"./fake/folder"}
46 1         self.fs.file_open = mock_open()
47 1         self.msg = Mock(MsgBase())
48         # create class
49 1         self.nslcmop_topic = NsLcmOpTopic(self.db, self.fs, self.msg, None)
50 1         self.nslcmop_topic.check_quota = Mock(return_value=None)  # skip quota
51
52 1         self.db.create_list("vim_accounts", yaml.safe_load(db_vim_accounts_text))
53 1         self.db.create_list("nsds", yaml.safe_load(db_nsds_text))
54 1         self.db.create_list("vnfds", yaml.safe_load(db_vnfds_text))
55 1         self.db.create_list("vnfrs", yaml.safe_load(db_vnfrs_text))
56 1         self.db.create_list("nsrs", yaml.safe_load(db_nsrs_text))
57 1         self.db.create = Mock(return_value="created_id")
58 1         self.nsd = self.db.get_list("nsds")[0]
59 1         self.nsd_id = self.nsd["_id"]
60 1         self.nsr = self.db.get_list("nsrs")[0]
61 1         self.nsr_id = self.nsr["_id"]
62 1         self.nsr_project = self.nsr["_admin"]["projects_read"][0]
63
64 1         self.vim = self.db.get_list("vim_accounts")[0]
65 1         self.vim_id = self.vim["_id"]
66
67 1     def test_create_instantiate(self):
68 1         self.db.set_one = Mock(return_value={"updated": 1})
69 1         session = {
70             "force": False,
71             "admin": False,
72             "public": False,
73             "project_id": [self.nsr_project],
74             "method": "write",
75         }
76 1         indata = {
77             "nsdId": self.nsd_id,
78             "nsInstanceId": self.nsr_id,
79             "nsName": "name",
80             "vimAccountId": self.vim_id,
81             "additionalParamsForVnf": [
82                 {
83                     "member-vnf-index": "1",
84                     "additionalParams": {"touch_filename": "file"},
85                 },
86                 {
87                     "member-vnf-index": "2",
88                     "additionalParams": {"touch_filename": "file"},
89                 },
90             ],
91             "vnf": [
92                 {
93                     "member-vnf-index": "1",
94                     "vdu": [
95                         {
96                             "id": "dataVM",
97                             "interface": [
98                                 {
99                                     "name": "dataVM-eth0",
100                                     "ip-address": "10.11.12.13",
101                                     "floating-ip-required": True,
102                                 }
103                             ],
104                         }
105                     ],
106                     "internal-vld": [
107                         {"name": "internal", "vim-network-id": "vim-net-id"}
108                     ],
109                 }
110             ],
111             "lcmOperationType": "instantiate",
112         }
113 1         rollback = []
114 1         headers = {}
115
116 1         nslcmop_id, _ = self.nslcmop_topic.new(
117             rollback, session, indata=deepcopy(indata), kwargs=None, headers=headers
118         )
119
120         # check nslcmop is created at database
121 1         self.assertEqual(
122             self.db.create.call_count,
123             1,
124             "database create not called, or called more than once",
125         )
126 1         _call = self.db.create.call_args_list[0]
127 1         self.assertEqual(
128             _call[0][0], "nslcmops", "must be create a nslcmops entry at database"
129         )
130
131 1         created_nslcmop = _call[0][1]
132 1         self.assertEqual(
133             nslcmop_id,
134             created_nslcmop["_id"],
135             "mismatch between return id and database '_id'",
136         )
137 1         self.assertEqual(
138             self.nsr_id,
139             created_nslcmop["nsInstanceId"],
140             "bad reference id from nslcmop to nsr",
141         )
142 1         self.assertTrue(
143             created_nslcmop["_admin"].get("projects_read"),
144             "Database record must contain '_amdin.projects_read'",
145         )
146 1         self.assertIn(
147             "created",
148             created_nslcmop["_admin"],
149             "Database record must contain '_admin.created'",
150         )
151 1         self.assertTrue(
152             created_nslcmop["lcmOperationType"] == "instantiate",
153             "Database record must contain 'lcmOperationType=instantiate'",
154         )
155
156 1         self.assertEqual(
157             len(rollback),
158             len(self.db.set_one.call_args_list) + 1,
159             "rollback mismatch with created/set items at database",
160         )
161
162         # test parameters with error
163 1         bad_id = "88d90b0c-faff-4b9f-bccd-aaaaaaaaaaaa"
164 1         test_set = (
165             (
166                 "nsr not found",
167                 {"nsInstanceId": bad_id},
168                 DbException,
169                 HTTPStatus.NOT_FOUND,
170                 ("not found", bad_id),
171             ),
172             # TODO add "nsd"
173             # ({"vimAccountId": bad_id}, DbException, HTTPStatus.NOT_FOUND, ("not found", bad_id)),  # TODO add "vim"
174             (
175                 "bad member-vnf-index",
176                 {"vnf.0.member-vnf-index": "k"},
177                 EngineException,
178                 HTTPStatus.BAD_REQUEST,
179                 ("k",),
180             ),
181         )
182 1         for message, kwargs_, expect_exc, expect_code, expect_text_list in test_set:
183 1             with self.assertRaises(expect_exc, msg=message) as e:
184 1                 self.nslcmop_topic.new(
185                     rollback,
186                     session,
187                     indata=deepcopy(indata),
188                     kwargs=kwargs_,
189                     headers=headers,
190                 )
191 1             if expect_code:
192 1                 self.assertTrue(e.exception.http_code == expect_code)
193 1             if expect_text_list:
194 1                 for expect_text in expect_text_list:
195 1                     self.assertIn(
196                         expect_text,
197                         str(e.exception).lower(),
198                         "Expected '{}' at exception text".format(expect_text),
199                     )
200
201 1     def test_check_ns_operation_action(self):
202 1         nsrs = self.db.get_list("nsrs")[0]
203 1         session = {}
204
205 1         indata = {
206             "member_vnf_index": "1",
207             "vdu_id": None,
208             "primitive": "touch",
209             "primitive_params": {"filename": "file"},
210         }
211
212 1         self.nslcmop_topic._check_ns_operation(session, nsrs, "action", indata)
213 1         for k in indata:
214 1             indata_copy = indata.copy()
215 1             if k == "primitive_params":
216 1                 continue
217 1             indata_copy[k] = "non_existing"
218 1             with self.assertRaises(EngineException) as exc_manager:
219 1                 self.nslcmop_topic._check_ns_operation(
220                     session, nsrs, "action", indata_copy
221                 )
222 1             exc = exc_manager.exception
223 1             self.assertEqual(
224                 exc.http_code,
225                 HTTPStatus.BAD_REQUEST,
226                 "Engine exception bad http_code with {}".format(indata_copy),
227             )
228
229 1     def test_update_remove_vnf(self):
230 1         vnfr_id = self.db.get_list("vnfrs")[0]["_id"]
231 1         session = {}
232 1         self.db.set_one(
233             "nsrs",
234             {"_id": self.nsr_id},
235             {"_admin.nsState": "INSTANTIATED"},
236         )
237 1         indata = {
238             "lcmOperationType": "update",
239             "updateType": "REMOVE_VNF",
240             "nsInstanceId": self.nsr_id,
241             "removeVnfInstanceId": vnfr_id,
242         }
243
244 1         session = {
245             "force": False,
246             "admin": False,
247             "public": False,
248             "project_id": [self.nsr_project],
249             "method": "write",
250         }
251 1         rollback = []
252 1         headers = {}
253
254 1         nslcmop_id, _ = self.nslcmop_topic.new(
255             rollback, session, indata, kwargs=None, headers=headers
256         )
257
258 1         self.assertEqual(
259             self.db.create.call_count,
260             1,
261             "database create not called, or called more than once",
262         )
263 1         _call = self.db.create.call_args_list[0]
264 1         self.assertEqual(
265             _call[0][0], "nslcmops", "nslcmops entry must be created at database"
266         )
267 1         created_nslcmop = _call[0][1]
268 1         self.assertEqual(
269             self.nsr_id,
270             created_nslcmop["nsInstanceId"],
271             "mismatch between nsId '_id' in created nslcmop and database nsr",
272         )
273 1         self.assertTrue(
274             created_nslcmop["lcmOperationType"] == "update",
275             "Database record must contain 'lcmOperationType=update'",
276         )
277 1         self.assertTrue(
278             created_nslcmop["operationParams"]["updateType"] == "REMOVE_VNF",
279             "Database record must contain 'updateType=REMOVE_VNF'",
280         )
281
282 1     def test_migrate(self):
283 1         _ = self.db.get_list("vnfrs")[0]["_id"]
284 1         session = {}
285 1         self.db.set_one(
286             "nsrs",
287             {"_id": self.nsr_id},
288             {"_admin.nsState": "INSTANTIATED"},
289         )
290 1         session = {
291             "force": False,
292             "admin": False,
293             "public": False,
294             "project_id": [self.nsr_project],
295             "method": "write",
296         }
297 1         rollback = []
298 1         headers = {}
299
300 1         with self.subTest(i=1, t="Migration for Specific VM"):
301 1             indata = {
302                 "lcmOperationType": "migrate",
303                 "nsInstanceId": self.nsr_id,
304                 "migrateToHost": "sample02",
305                 "vdu": {"vduCountIndex": 0, "vduId": "mgmtVM"},
306                 "vnfInstanceId": "9e8006df-cdfa-4f63-bf6a-fce860d71c1f",
307             }
308 1             nslcmop_id, _ = self.nslcmop_topic.new(
309                 rollback, session, indata, kwargs=None, headers=headers
310             )
311
312 1             self.assertEqual(
313                 self.db.create.call_count,
314                 1,
315                 "database create not called, or called more than once",
316             )
317 1             _call = self.db.create.call_args_list[0]
318 1             self.assertEqual(
319                 _call[0][0], "nslcmops", "nslcmops entry must be created at database"
320             )
321 1             created_nslcmop = _call[0][1]
322 1             self.assertEqual(
323                 self.nsr_id,
324                 created_nslcmop["nsInstanceId"],
325                 "mismatch between nsId '_id' in created nslcmop and database nsr",
326             )
327 1             self.assertTrue(
328                 created_nslcmop["lcmOperationType"] == "migrate",
329                 "Database record must contain 'lcmOperationType=migrate'",
330             )
331 1         with self.subTest(i=2, t="Migration of all VDUs in a VNF"):
332 1             indata = {
333                 "lcmOperationType": "migrate",
334                 "nsInstanceId": self.nsr_id,
335                 "vnfInstanceId": "9e8006df-cdfa-4f63-bf6a-fce860d71c1f",
336             }
337 1             nslcmop_id, _ = self.nslcmop_topic.new(
338                 rollback, session, indata, kwargs=None, headers=headers
339             )
340
341 1             self.assertEqual(
342                 self.db.create.call_count,
343                 2,
344                 "database create not called, or called more than once",
345             )
346 1             _call = self.db.create.call_args_list[0]
347 1             self.assertEqual(
348                 _call[0][0], "nslcmops", "nslcmops entry must be created at database"
349             )
350 1             created_nslcmop = _call[0][1]
351 1             self.assertEqual(
352                 self.nsr_id,
353                 created_nslcmop["nsInstanceId"],
354                 "mismatch between nsId '_id' in created nslcmop and database nsr",
355             )
356 1             self.assertTrue(
357                 created_nslcmop["lcmOperationType"] == "migrate",
358                 "Database record must contain 'lcmOperationType=migrate'",
359             )
360 1         with self.subTest(i=3, t="Migration failure - vduId not provided in vdu "):
361 1             indata = {
362                 "lcmOperationType": "migrate",
363                 "nsInstanceId": self.nsr_id,
364                 "migrateToHost": "sample02",
365                 "vdu": {"vduCountIndex": 0},
366                 "vnfInstanceId": "9e8006df-cdfa-4f63-bf6a-fce860d71c1f",
367             }
368
369 1             with self.assertRaises(Exception) as e:
370 1                 nslcmop_id, _ = self.nslcmop_topic.new(
371                     rollback, session, indata, kwargs=None, headers=headers
372                 )
373 1             self.assertTrue(
374                 "Format error at 'vdu' ''vduId' is a required property'"
375                 in str(e.exception)
376             )
377
378
379 1 class TestNsLcmOpTopicWithMock(unittest.TestCase):
380 1     def setUp(self):
381 1         self.db = Mock(dbbase.DbBase())
382 1         self.fs = Mock(FsBase())
383 1         self.fs.get_params.return_value = {"./fake/folder"}
384 1         self.fs.file_open = mock_open()
385 1         self.msg = Mock(MsgBase())
386         # create class
387 1         self.nslcmop_topic = NsLcmOpTopic(self.db, self.fs, self.msg, None)
388
389 1     def test_get_vnfd_from_vnf_member_revision(self):
390 1         test_vnfr = yaml.safe_load(db_vnfrs_text)[0]
391 1         test_vnfd = yaml.safe_load(db_vnfds_text)
392 1         self.db.get_one.side_effect = [test_vnfr, test_vnfd]
393 1         _ = self.nslcmop_topic._get_vnfd_from_vnf_member_index("1", test_vnfr["_id"])
394 1         self.assertEqual(
395             self.db.get_one.call_args_list[0][0][0],
396             "vnfrs",
397             "Incorrect first DB lookup",
398         )
399 1         self.assertEqual(
400             self.db.get_one.call_args_list[1][0][0],
401             "vnfds",
402             "Incorrect second DB lookup",
403         )
404
405 1     def test_get_vnfd_from_vnf_member_no_revision(self):
406 1         test_vnfr = yaml.safe_load(db_vnfrs_text)[0]
407 1         test_vnfr["revision"] = 3
408 1         test_vnfd = yaml.safe_load(db_vnfds_text)
409 1         self.db.get_one.side_effect = [test_vnfr, test_vnfd]
410 1         _ = self.nslcmop_topic._get_vnfd_from_vnf_member_index("1", test_vnfr["_id"])
411 1         self.assertEqual(
412             self.db.get_one.call_args_list[0][0][0],
413             "vnfrs",
414             "Incorrect first DB lookup",
415         )
416 1         self.assertEqual(
417             self.db.get_one.call_args_list[1][0][0],
418             "vnfds_revisions",
419             "Incorrect second DB lookup",
420         )
421
422 1     @contextmanager
423 1     def assertNotRaises(self, exception_type):
424 1         try:
425 1             yield None
426 0         except exception_type:
427 0             raise self.failureException("{} raised".format(exception_type.__name__))
428
429 1     def test_check_ns_update_operation(self):
430 1         self.db = DbMemory()
431 1         self.nslcmop_topic = NsLcmOpTopic(self.db, self.fs, self.msg, None)
432 1         session = {}
433
434 1         with self.subTest(i=1, t="VNF instance does not belong to NS"):
435 1             test_vnfr = yaml.safe_load(db_vnfrs_text)
436 1             test_vnfr[0]["revision"] = 2
437 1             test_nsr = yaml.safe_load(db_nsrs_text)
438 1             test_nsr[0]["constituent-vnfr-ref"][
439                 0
440             ] = "99d90b0c-faff-4b9f-bccd-017f33985984"
441 1             self.db.create_list("vnfrs", test_vnfr)
442 1             self.db.create_list("nsrs", test_nsr)
443 1             nsrs = self.db.get_list("nsrs")[0]
444 1             indata = {
445                 "updateType": "CHANGE_VNFPKG",
446                 "changeVnfPackageData": {
447                     "vnfInstanceId": "88d90b0c-faff-4b9f-bccd-017f33985984",
448                     "vnfdId": "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77",
449                 },
450                 "nsInstanceId": "f48163a6-c807-47bc-9682-f72caef5af85",
451             }
452 1             with self.assertRaises(EngineException) as expected_exception:
453 1                 self.nslcmop_topic._check_ns_operation(session, nsrs, "update", indata)
454 1             self.assertEqual(
455                 str(expected_exception.exception),
456                 "Error in validating ns-update request: vnf 88d90b0c-faff-4b9f-bccd-017f33985984"
457                 " does not belong to NS f48163a6-c807-47bc-9682-f72caef5af85",
458             )
459
460 1         with self.subTest(i=2, t="Ns update request validated with no exception"):
461 1             test_vnfr = yaml.safe_load(db_vnfrs_text)
462 1             test_vnfr[0]["revision"] = 2
463 1             test_nsr = yaml.safe_load(db_nsrs_text)
464 1             self.db.create_list("vnfrs", test_vnfr)
465 1             self.db.create_list("nsrs", test_nsr)
466 1             nsrs = self.db.get_list("nsrs")[1]
467 1             indata = {
468                 "updateType": "CHANGE_VNFPKG",
469                 "changeVnfPackageData": {
470                     "vnfInstanceId": "88d90b0c-faff-4b9f-bccd-017f33985984",
471                     "vnfdId": "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77",
472                 },
473                 "nsInstanceId": "f48163a6-c807-47bc-9682-f72caef5af85",
474             }
475 1             with self.assertNotRaises(EngineException):
476 1                 self.nslcmop_topic._check_ns_operation(session, nsrs, "update", indata)
477
478 1         with self.subTest(
479             i=3, t="Ns update request rejected because of too small timeout"
480         ):
481 1             indata = {
482                 "updateType": "CHANGE_VNFPKG",
483                 "changeVnfPackageData": {
484                     "vnfInstanceId": "88d90b0c-faff-4b9f-bccd-017f33985984",
485                     "vnfdId": "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77",
486                 },
487                 "nsInstanceId": "f48163a6-c807-47bc-9682-f72caef5af85",
488                 "timeout_ns_update": 50,
489             }
490 1             with self.assertRaises(EngineException) as expected_exception:
491 1                 self.nslcmop_topic._check_ns_operation(session, nsrs, "update", indata)
492 1             self.assertEqual(
493                 str(expected_exception.exception),
494                 "Error in validating ns-update request: 50 second is not enough "
495                 "to upgrade the VNF instance: 88d90b0c-faff-4b9f-bccd-017f33985984",
496             )
497
498 1         with self.subTest(i=4, t="wrong vnfdid is given as an update parameter"):
499 1             test_vnfr = yaml.safe_load(db_vnfrs_text)
500 1             test_vnfr[0]["revision"] = 2
501 1             test_nsr = yaml.safe_load(db_nsrs_text)
502 1             self.db.create_list("vnfrs", test_vnfr)
503 1             self.db.create_list("nsrs", test_nsr)
504 1             nsrs = self.db.get_list("nsrs")[2]
505 1             indata = {
506                 "updateType": "CHANGE_VNFPKG",
507                 "changeVnfPackageData": {
508                     "vnfInstanceId": "88d90b0c-faff-4b9f-bccd-017f33985984",
509                     "vnfdId": "9637bcf8-cf14-42dc-ad70-c66fcf1e6e77",
510                 },
511                 "nsInstanceId": "f48163a6-c807-47bc-9682-f72caef5af85",
512             }
513 1             with self.assertRaises(EngineException) as expected_exception:
514 1                 self.nslcmop_topic._check_ns_operation(session, nsrs, "update", indata)
515 1             self.assertEqual(
516                 str(expected_exception.exception),
517                 "Error in validating ns-update request: vnfd-id 9637bcf8-cf14-42dc-ad70-c66fcf1e6e77 does not "
518                 "match with the vnfd-id: 7637bcf8-cf14-42dc-ad70-c66fcf1e6e77 of "
519                 "VNF instance: 88d90b0c-faff-4b9f-bccd-017f33985984",
520             )
521
522 1         with self.subTest(
523             i=5, t="Ns update REMOVE_VNF request validated with no exception"
524         ):
525 1             test_vnfr = yaml.safe_load(db_vnfrs_text)
526 1             test_vnfr[0]["revision"] = 2
527 1             test_nsr = yaml.safe_load(db_nsrs_text)
528 1             self.db.create_list("vnfrs", test_vnfr)
529 1             self.db.create_list("nsrs", test_nsr)
530 1             nsrs = self.db.get_list("nsrs")[1]
531 1             indata = {
532                 "updateType": "REMOVE_VNF",
533                 "removeVnfInstanceId": "88d90b0c-faff-4b9f-bccd-017f33985984",
534                 "nsInstanceId": "f48163a6-c807-47bc-9682-f72caef5af85",
535             }
536 1             with self.assertNotRaises(EngineException):
537 1                 self.nslcmop_topic._check_ns_operation(session, nsrs, "update", indata)
538
539
540 1 class TestNsrTopic(unittest.TestCase):
541 1     def setUp(self):
542 1         self.db = DbMemory()
543 1         self.fs = Mock(FsBase())
544 1         self.fs.get_params.return_value = {"./fake/folder"}
545 1         self.fs.file_open = mock_open()
546 1         self.msg = Mock(MsgBase())
547         # create class
548 1         self.nsr_topic = NsrTopic(self.db, self.fs, self.msg, None)
549 1         self.nsr_topic.check_quota = Mock(return_value=None)  # skip quota
550
551 1         self.db.create_list("vim_accounts", yaml.safe_load(db_vim_accounts_text))
552 1         self.db.create_list("nsds", yaml.safe_load(db_nsds_text))
553 1         self.db.create_list("vnfds", yaml.safe_load(db_vnfds_text))
554 1         self.db.create = Mock(return_value="created_id")
555 1         self.nsd = self.db.get_list("nsds")[0]
556 1         self.nsd_id = self.nsd["_id"]
557 1         self.nsd_project = self.nsd["_admin"]["projects_read"][0]
558
559 1         self.vim = self.db.get_list("vim_accounts")[0]
560 1         self.vim_id = self.vim["_id"]
561
562 1     def test_create(self):
563 1         session = {
564             "force": False,
565             "admin": False,
566             "public": False,
567             "project_id": [self.nsd_project],
568             "method": "write",
569         }
570 1         indata = {
571             "nsdId": self.nsd_id,
572             "nsName": "name",
573             "vimAccountId": self.vim_id,
574             "additionalParamsForVnf": [
575                 {
576                     "member-vnf-index": "hackfest_vnf1",
577                     "additionalParams": {"touch_filename": "file"},
578                 },
579                 {
580                     "member-vnf-index": "hackfest_vnf2",
581                     "additionalParams": {"touch_filename": "file"},
582                 },
583             ],
584         }
585 1         rollback = []
586 1         headers = {}
587
588 1         self.nsr_topic.new(
589             rollback, session, indata=indata, kwargs=None, headers=headers
590         )
591
592         # check vnfrs and nsrs created in whatever order
593 1         created_vnfrs = []
594 1         created_nsrs = []
595 1         nsr_id = None
596 1         for _call in self.db.create.call_args_list:
597 1             assert len(_call[0]) >= 2, "called db.create with few parameters"
598 1             created_item = _call[0][1]
599 1             if _call[0][0] == "vnfrs":
600 1                 created_vnfrs.append(created_item)
601 1                 self.assertIn(
602                     "member-vnf-index-ref",
603                     created_item,
604                     "Created item must contain member-vnf-index-ref section",
605                 )
606 1                 if nsr_id:
607 1                     self.assertEqual(
608                         nsr_id,
609                         created_item["nsr-id-ref"],
610                         "bad reference id from vnfr to nsr",
611                     )
612                 else:
613 1                     nsr_id = created_item["nsr-id-ref"]
614
615 1             elif _call[0][0] == "nsrs":
616 1                 created_nsrs.append(created_item)
617 1                 if nsr_id:
618 1                     self.assertEqual(
619                         nsr_id, created_item["_id"], "bad reference id from vnfr to nsr"
620                     )
621                 else:
622 0                     nsr_id = created_item["_id"]
623             else:
624 0                 assert True, "created an unknown record {} at database".format(
625                     _call[0][0]
626                 )
627
628 1             self.assertTrue(
629                 created_item["_admin"].get("projects_read"),
630                 "Database record must contain '_amdin.projects_read'",
631             )
632 1             self.assertIn(
633                 "created",
634                 created_item["_admin"],
635                 "Database record must contain '_admin.created'",
636             )
637 1             self.assertTrue(
638                 created_item["_admin"]["nsState"] == "NOT_INSTANTIATED",
639                 "Database record must contain '_admin.nstate=NOT INSTANTIATE'",
640             )
641
642 1         self.assertEqual(
643             len(created_vnfrs), 2, "created a mismatch number of vnfr at database"
644         )
645
646 1         self.assertEqual(
647             created_vnfrs[0]["vdur"][0]["interfaces"][0]["position"],
648             1,
649             "vdur first interface position does not match",
650         )
651
652 1         self.assertEqual(
653             created_vnfrs[0]["vdur"][0]["interfaces"][1]["position"],
654             2,
655             "vdur second interface position does not match",
656         )
657
658 1         self.assertEqual(
659             len(created_nsrs), 1, "Only one nsrs must be created at database"
660         )
661 1         self.assertEqual(
662             len(rollback),
663             len(created_vnfrs) + 1,
664             "rollback mismatch with created items at database",
665         )
666
667         # test parameters with error
668 1         bad_id = "88d90b0c-faff-4b9f-bccd-aaaaaaaaaaaa"
669 1         test_set = (
670             # TODO add "nsd"
671             (
672                 "nsd not found",
673                 {"nsdId": bad_id},
674                 DbException,
675                 HTTPStatus.NOT_FOUND,
676                 ("not found", bad_id),
677             ),
678             # ({"vimAccountId": bad_id}, DbException, HTTPStatus.NOT_FOUND, ("not found", bad_id)),  # TODO add "vim"
679             (
680                 "additional params not supply",
681                 {"additionalParamsForVnf.0.member-vnf-index": "k"},
682                 EngineException,
683                 HTTPStatus.BAD_REQUEST,
684                 None,
685             ),
686         )
687 1         for message, kwargs_, expect_exc, expect_code, expect_text_list in test_set:
688 1             with self.assertRaises(expect_exc, msg=message) as e:
689 1                 self.nsr_topic.new(
690                     rollback,
691                     session,
692                     indata=deepcopy(indata),
693                     kwargs=kwargs_,
694                     headers=headers,
695                 )
696 1             if expect_code:
697 1                 self.assertTrue(e.exception.http_code == expect_code)
698 1             if expect_text_list:
699 1                 for expect_text in expect_text_list:
700 1                     self.assertIn(
701                         expect_text,
702                         str(e.exception).lower(),
703                         "Expected '{}' at exception text".format(expect_text),
704                     )
705
706 1     def test_show_instance(self):
707 1         session = {
708             "force": False,
709             "admin": False,
710             "public": False,
711             "project_id": [self.nsd_project],
712             "method": "write",
713         }
714 1         filter_q = {}
715 1         for refresh_status in ("true", "false"):
716 1             self.db.create_list("nsrs", yaml.safe_load(db_nsrs_text))
717 1             actual_nsr = self.db.get_list("nsrs")[0]
718 1             nsr_id = actual_nsr["_id"]
719 1             filter_q["vcaStatus-refresh"] = refresh_status
720 1             expected_nsr = self.nsr_topic.show(session, nsr_id, filter_q=filter_q)
721 1             self.nsr_topic.delete(session, nsr_id)
722 1             actual_nsr.pop("_admin")
723 1             expected_nsr.pop("_admin")
724 1             self.assertEqual(
725                 expected_nsr, actual_nsr, "Database nsr and show() nsr do not match."
726             )
727
728 1     def test_vca_status_refresh(self):
729 1         session = {
730             "force": False,
731             "admin": False,
732             "public": False,
733             "project_id": [self.nsd_project],
734             "method": "write",
735         }
736 1         filter_q = {"vcaStatus-refresh": "true"}
737 1         time_delta = 120
738 1         self.db.create_list("nsrs", yaml.safe_load(db_nsrs_text))
739 1         nsr = self.db.get_list("nsrs")[0]
740
741         # When vcaStatus-refresh is true
742 1         filter_q["vcaStatus-refresh"] = "true"
743 1         self.nsr_topic.vca_status_refresh(session, nsr, filter_q)
744 1         msg_args = self.msg.write.call_args[0]
745 1         self.assertEqual(msg_args[1], "vca_status_refresh", "Wrong message action")
746 1         self.assertGreater(nsr["_admin"]["modified"], time() - time_delta)
747
748         # When vcaStatus-refresh is false but modified time is within threshold
749 1         filter_q["vcaStatus-refresh"] = "false"
750 1         time_now = time()
751 1         nsr["_admin"]["modified"] = time_now
752 1         self.nsr_topic.vca_status_refresh(session, nsr, filter_q)
753 1         msg_args = self.msg.write.call_args[1]
754 1         self.assertEqual(msg_args, {}, "Message should not be sent.")
755 1         self.assertEqual(
756             nsr["_admin"]["modified"], time_now, "Modified time should not be changed."
757         )
758
759         # When vcaStatus-refresh is false but modified time is less than threshold
760 1         filter_q["vcaStatus-refresh"] = "false"
761 1         nsr["_admin"]["modified"] = time() - (2 * time_delta)
762 1         self.nsr_topic.vca_status_refresh(session, nsr, filter_q)
763 1         msg_args = self.msg.write.call_args[0]
764 1         self.assertEqual(msg_args[1], "vca_status_refresh", "Wrong message action")
765 1         self.nsr_topic.delete(session, nsr["_id"])
766 1         self.assertGreater(
767             nsr["_admin"]["modified"],
768             time() - time_delta,
769             "Modified time is not changed.",
770         )
771
772 1     def test_delete_ns(self):
773 1         self.db.create_list("nsrs", yaml.safe_load(db_nsrs_text))
774 1         self.nsr = self.db.get_list("nsrs")[0]
775 1         self.nsr_id = self.nsr["_id"]
776 1         self.db_set_one = self.db.set_one
777 1         p_id = self.nsd_project
778 1         p_other = "other_p"
779
780 1         session = {
781             "force": False,
782             "admin": False,
783             "public": None,
784             "project_id": [p_id],
785             "method": "delete",
786         }
787 1         session2 = {
788             "force": False,
789             "admin": False,
790             "public": None,
791             "project_id": [p_other],
792             "method": "delete",
793         }
794 1         session_force = {
795             "force": True,
796             "admin": True,
797             "public": None,
798             "project_id": [],
799             "method": "delete",
800         }
801 1         with self.subTest(i=1, t="Normal Deletion"):
802 1             self.db.del_one = Mock()
803 1             self.db.set_one = Mock()
804 1             self.nsr_topic.delete(session, self.nsr_id)
805
806 1             db_args_ro_nsrs = self.db.del_one.call_args_list[1][0]
807 1             db_args = self.db.del_one.call_args_list[0][0]
808 1             msg_args = self.msg.write.call_args[0]
809 1             self.assertEqual(
810                 msg_args[0], self.nsr_topic.topic_msg, "Wrong message topic"
811             )
812 1             self.assertEqual(msg_args[1], "deleted", "Wrong message action")
813 1             self.assertEqual(msg_args[2], {"_id": self.nsr_id}, "Wrong message content")
814 1             self.assertEqual(db_args_ro_nsrs[0], "ro_nsrs", "Wrong DB topic")
815 1             self.assertEqual(db_args[0], self.nsr_topic.topic, "Wrong DB topic")
816 1             self.assertEqual(db_args[1]["_id"], self.nsr_id, "Wrong DB ID")
817 1             self.assertEqual(
818                 db_args[1]["_admin.projects_read.cont"], [p_id], "Wrong DB filter"
819             )
820 1             self.db.set_one.assert_not_called()
821 1             fs_del_calls = self.fs.file_delete.call_args_list
822 1             self.assertEqual(fs_del_calls[0][0][0], self.nsr_id, "Wrong FS file id")
823 1         with self.subTest(i=2, t="No delete because referenced by other project"):
824 1             self.db_set_one(
825                 "nsrs",
826                 {"_id": self.nsr_id},
827                 update_dict=None,
828                 push={
829                     "_admin.projects_read": p_other,
830                     "_admin.projects_write": p_other,
831                 },
832             )
833 1             self.db.del_one.reset_mock()
834 1             self.db.set_one.reset_mock()
835 1             self.msg.write.reset_mock()
836 1             self.fs.file_delete.reset_mock()
837
838 1             self.nsr_topic.delete(session2, self.nsr_id)
839 1             self.db.del_one.assert_not_called()
840 1             self.msg.write.assert_not_called()
841 1             db_s1_args = self.db.set_one.call_args
842 1             self.assertEqual(db_s1_args[0][0], self.nsr_topic.topic, "Wrong DB topic")
843 1             self.assertEqual(db_s1_args[0][1]["_id"], self.nsr_id, "Wrong DB ID")
844 1             self.assertIsNone(
845                 db_s1_args[1]["update_dict"], "Wrong DB update dictionary"
846             )
847 1             self.assertEqual(
848                 db_s1_args[1]["pull_list"],
849                 {"_admin.projects_read": [p_other], "_admin.projects_write": [p_other]},
850                 "Wrong DB pull_list dictionary",
851             )
852 1             self.fs.file_delete.assert_not_called()
853 1         with self.subTest(i=4, t="Delete with force and admin"):
854 1             self.db.del_one.reset_mock()
855 1             self.db.set_one.reset_mock()
856 1             self.msg.write.reset_mock()
857 1             self.fs.file_delete.reset_mock()
858 1             self.nsr_topic.delete(session_force, self.nsr_id)
859
860 1             db_args_ro_nsrs = self.db.del_one.call_args_list[1][0]
861 1             db_args = self.db.del_one.call_args_list[0][0]
862 1             msg_args = self.msg.write.call_args[0]
863 1             self.assertEqual(
864                 msg_args[0], self.nsr_topic.topic_msg, "Wrong message topic"
865             )
866 1             self.assertEqual(msg_args[1], "deleted", "Wrong message action")
867 1             self.assertEqual(msg_args[2], {"_id": self.nsr_id}, "Wrong message content")
868 1             self.assertEqual(db_args_ro_nsrs[0], "ro_nsrs", "Wrong DB topic")
869 1             self.assertEqual(db_args[0], self.nsr_topic.topic, "Wrong DB topic")
870 1             self.assertEqual(db_args[1]["_id"], self.nsr_id, "Wrong DB ID")
871 1             self.db.set_one.assert_not_called()
872 1             fs_del_calls = self.fs.file_delete.call_args_list
873 1             self.assertEqual(fs_del_calls[0][0][0], self.nsr_id, "Wrong FS file id")
874 1         with self.subTest(i=3, t="Conflict on Delete - NS in INSTANTIATED state"):
875 1             self.db_set_one(
876                 "nsrs",
877                 {"_id": self.nsr_id},
878                 {"_admin.nsState": "INSTANTIATED"},
879                 pull={
880                     "_admin.projects_read": p_other,
881                     "_admin.projects_write": p_other,
882                 },
883             )
884 1             self.db.del_one.reset_mock()
885 1             self.db.set_one.reset_mock()
886 1             self.msg.write.reset_mock()
887 1             self.fs.file_delete.reset_mock()
888
889 1             with self.assertRaises(
890                 EngineException, msg="Accepted NSR with nsState INSTANTIATED"
891             ) as e:
892 1                 self.nsr_topic.delete(session, self.nsr_id)
893 1             self.assertEqual(
894                 e.exception.http_code, HTTPStatus.CONFLICT, "Wrong HTTP status code"
895             )
896 1             self.assertIn("INSTANTIATED", str(e.exception), "Wrong exception text")
897         # TODOD with self.subTest(i=3, t='Conflict on Delete - NS in use by NSI'):
898
899 1         with self.subTest(i=4, t="Non-existent NS"):
900 1             self.db.del_one.reset_mock()
901 1             self.db.set_one.reset_mock()
902 1             self.msg.write.reset_mock()
903 1             self.fs.file_delete.reset_mock()
904 1             excp_msg = "Not found"
905 1             with self.assertRaises(
906                 DbException, msg="Accepted non-existent NSD ID"
907             ) as e:
908 1                 self.nsr_topic.delete(session2, "other_id")
909 1             self.assertEqual(
910                 e.exception.http_code, HTTPStatus.NOT_FOUND, "Wrong HTTP status code"
911             )
912 1             self.assertIn(excp_msg, str(e.exception), "Wrong exception text")
913 1             self.assertIn("other_id", str(e.exception), "Wrong exception text")
914 1         return