blob: 2ecdbf72379c37d641fcd330cf24c2bb086f7414 [file] [log] [blame]
delacruzramo79e40f42019-10-10 16:36:40 +02001#! /usr/bin/python3
2# -*- coding: utf-8 -*-
3
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13# implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17__author__ = "Pedro de la Cruz Ramos, pedro.delacruzramos@altran.com"
18__date__ = "$2019-10-019"
19
20import unittest
selvi.j0389d9e2023-04-26 12:13:10 +000021import random
delacruzramo79e40f42019-10-10 16:36:40 +020022from unittest import TestCase
David Garciaecb41322021-03-31 19:10:46 +020023from unittest.mock import Mock, patch, call
delacruzramo79e40f42019-10-10 16:36:40 +020024from uuid import uuid4
25from http import HTTPStatus
26from time import time
delacruzramo79e40f42019-10-10 16:36:40 +020027from osm_common import dbbase, fsbase, msgbase
garciadeblas6d83f8f2023-06-19 22:34:49 +020028from osm_common.dbmemory import DbMemory
delacruzramo79e40f42019-10-10 16:36:40 +020029from osm_nbi import authconn, validation
David Garciaecb41322021-03-31 19:10:46 +020030from osm_nbi.admin_topics import (
31 ProjectTopicAuth,
32 RoleTopicAuth,
33 UserTopicAuth,
34 CommonVimWimSdn,
35 VcaTopic,
36)
delacruzramo79e40f42019-10-10 16:36:40 +020037from osm_nbi.engine import EngineException
38from osm_nbi.authconn import AuthconnNotFoundException
garciadeblas6d83f8f2023-06-19 22:34:49 +020039from osm_nbi.authconn_internal import AuthconnInternal
delacruzramo79e40f42019-10-10 16:36:40 +020040
41
42test_pid = str(uuid4())
43test_name = "test-user"
44
45
46def norm(str):
47 """Normalize string for checking"""
garciadeblas4568a372021-03-24 09:19:48 +010048 return " ".join(str.strip().split()).lower()
delacruzramo79e40f42019-10-10 16:36:40 +020049
50
David Garciaecb41322021-03-31 19:10:46 +020051class TestVcaTopic(TestCase):
52 def setUp(self):
53 self.db = Mock(dbbase.DbBase())
54 self.fs = Mock(fsbase.FsBase())
55 self.msg = Mock(msgbase.MsgBase())
56 self.auth = Mock(authconn.Authconn(None, None, None))
57 self.vca_topic = VcaTopic(self.db, self.fs, self.msg, self.auth)
58
59 @patch("osm_nbi.admin_topics.CommonVimWimSdn.format_on_new")
60 def test_format_on_new(self, mock_super_format_on_new):
61 content = {
62 "_id": "id",
63 "secret": "encrypted_secret",
64 "cacert": "encrypted_cacert",
65 }
66 self.db.encrypt.side_effect = ["secret", "cacert"]
67 mock_super_format_on_new.return_value = "1234"
68
69 oid = self.vca_topic.format_on_new(content)
70
71 self.assertEqual(oid, "1234")
72 self.assertEqual(content["secret"], "secret")
73 self.assertEqual(content["cacert"], "cacert")
74 self.db.encrypt.assert_has_calls(
75 [
76 call("encrypted_secret", schema_version="1.11", salt="id"),
77 call("encrypted_cacert", schema_version="1.11", salt="id"),
78 ]
79 )
80 mock_super_format_on_new.assert_called_with(content, None, False)
81
82 @patch("osm_nbi.admin_topics.CommonVimWimSdn.format_on_edit")
83 def test_format_on_edit(self, mock_super_format_on_edit):
84 edit_content = {
85 "_id": "id",
86 "secret": "encrypted_secret",
87 "cacert": "encrypted_cacert",
88 }
89 final_content = {
90 "_id": "id",
91 "schema_version": "1.11",
92 }
93 self.db.encrypt.side_effect = ["secret", "cacert"]
94 mock_super_format_on_edit.return_value = "1234"
95
96 oid = self.vca_topic.format_on_edit(final_content, edit_content)
97
98 self.assertEqual(oid, "1234")
99 self.assertEqual(final_content["secret"], "secret")
100 self.assertEqual(final_content["cacert"], "cacert")
101 self.db.encrypt.assert_has_calls(
102 [
103 call("encrypted_secret", schema_version="1.11", salt="id"),
104 call("encrypted_cacert", schema_version="1.11", salt="id"),
105 ]
106 )
107 mock_super_format_on_edit.assert_called()
108
109 @patch("osm_nbi.admin_topics.CommonVimWimSdn.check_conflict_on_del")
110 def test_check_conflict_on_del(self, mock_check_conflict_on_del):
111 session = {
112 "project_id": "project-id",
113 "force": False,
114 }
115 _id = "vca-id"
116 db_content = {}
117
118 self.db.get_list.return_value = None
119
120 self.vca_topic.check_conflict_on_del(session, _id, db_content)
121
122 self.db.get_list.assert_called_with(
123 "vim_accounts",
garciadeblas4568a372021-03-24 09:19:48 +0100124 {"vca": _id, "_admin.projects_read.cont": "project-id"},
David Garciaecb41322021-03-31 19:10:46 +0200125 )
126 mock_check_conflict_on_del.assert_called_with(session, _id, db_content)
127
128 @patch("osm_nbi.admin_topics.CommonVimWimSdn.check_conflict_on_del")
129 def test_check_conflict_on_del_force(self, mock_check_conflict_on_del):
130 session = {
131 "project_id": "project-id",
132 "force": True,
133 }
134 _id = "vca-id"
135 db_content = {}
136
137 self.vca_topic.check_conflict_on_del(session, _id, db_content)
138
139 self.db.get_list.assert_not_called()
140 mock_check_conflict_on_del.assert_not_called()
141
142 @patch("osm_nbi.admin_topics.CommonVimWimSdn.check_conflict_on_del")
143 def test_check_conflict_on_del_with_conflict(self, mock_check_conflict_on_del):
144 session = {
145 "project_id": "project-id",
146 "force": False,
147 }
148 _id = "vca-id"
149 db_content = {}
150
151 self.db.get_list.return_value = {"_id": "vim", "vca": "vca-id"}
152
153 with self.assertRaises(EngineException) as context:
154 self.vca_topic.check_conflict_on_del(session, _id, db_content)
155 self.assertEqual(
156 context.exception,
157 EngineException(
158 "There is at least one VIM account using this vca",
garciadeblas4568a372021-03-24 09:19:48 +0100159 http_code=HTTPStatus.CONFLICT,
160 ),
David Garciaecb41322021-03-31 19:10:46 +0200161 )
162
163 self.db.get_list.assert_called_with(
164 "vim_accounts",
garciadeblas4568a372021-03-24 09:19:48 +0100165 {"vca": _id, "_admin.projects_read.cont": "project-id"},
David Garciaecb41322021-03-31 19:10:46 +0200166 )
167 mock_check_conflict_on_del.assert_not_called()
168
169
delacruzramo79e40f42019-10-10 16:36:40 +0200170class Test_ProjectTopicAuth(TestCase):
delacruzramo79e40f42019-10-10 16:36:40 +0200171 @classmethod
172 def setUpClass(cls):
173 cls.test_name = "test-project-topic"
174
175 def setUp(self):
176 self.db = Mock(dbbase.DbBase())
177 self.fs = Mock(fsbase.FsBase())
178 self.msg = Mock(msgbase.MsgBase())
tierno9e87a7f2020-03-23 09:24:10 +0000179 self.auth = Mock(authconn.Authconn(None, None, None))
delacruzramo79e40f42019-10-10 16:36:40 +0200180 self.topic = ProjectTopicAuth(self.db, self.fs, self.msg, self.auth)
garciadeblas4568a372021-03-24 09:19:48 +0100181 self.fake_session = {
182 "username": self.test_name,
183 "project_id": (test_pid,),
184 "method": None,
185 "admin": True,
186 "force": False,
187 "public": False,
188 "allow_show_user_project_role": True,
189 }
tiernod7749582020-05-28 10:41:10 +0000190 self.topic.check_quota = Mock(return_value=None) # skip quota
delacruzramo79e40f42019-10-10 16:36:40 +0200191
192 def test_new_project(self):
193 with self.subTest(i=1):
194 rollback = []
195 pid1 = str(uuid4())
196 self.auth.get_project_list.return_value = []
197 self.auth.create_project.return_value = pid1
garciadeblas4568a372021-03-24 09:19:48 +0100198 pid2, oid = self.topic.new(
199 rollback, self.fake_session, {"name": self.test_name, "quotas": {}}
200 )
delacruzramo79e40f42019-10-10 16:36:40 +0200201 self.assertEqual(len(rollback), 1, "Wrong rollback length")
202 self.assertEqual(pid2, pid1, "Wrong project identifier")
203 content = self.auth.create_project.call_args[0][0]
204 self.assertEqual(content["name"], self.test_name, "Wrong project name")
205 self.assertEqual(content["quotas"], {}, "Wrong quotas")
206 self.assertIsNotNone(content["_admin"]["created"], "Wrong creation time")
garciadeblas4568a372021-03-24 09:19:48 +0100207 self.assertEqual(
208 content["_admin"]["modified"],
209 content["_admin"]["created"],
210 "Wrong modification time",
211 )
delacruzramo79e40f42019-10-10 16:36:40 +0200212 with self.subTest(i=2):
213 rollback = []
214 with self.assertRaises(EngineException, msg="Accepted wrong quotas") as e:
garciadeblas4568a372021-03-24 09:19:48 +0100215 self.topic.new(
216 rollback,
217 self.fake_session,
218 {"name": "other-project-name", "quotas": {"baditems": 10}},
219 )
delacruzramo79e40f42019-10-10 16:36:40 +0200220 self.assertEqual(len(rollback), 0, "Wrong rollback length")
garciadeblas4568a372021-03-24 09:19:48 +0100221 self.assertEqual(
222 e.exception.http_code,
223 HTTPStatus.UNPROCESSABLE_ENTITY,
224 "Wrong HTTP status code",
225 )
226 self.assertIn(
227 "format error at 'quotas' 'additional properties are not allowed ('{}' was unexpected)'".format(
228 "baditems"
229 ),
230 norm(str(e.exception)),
231 "Wrong exception text",
232 )
delacruzramo79e40f42019-10-10 16:36:40 +0200233
234 def test_edit_project(self):
235 now = time()
236 pid = str(uuid4())
garciadeblas4568a372021-03-24 09:19:48 +0100237 proj = {
238 "_id": pid,
239 "name": self.test_name,
240 "_admin": {"created": now, "modified": now},
241 }
delacruzramo79e40f42019-10-10 16:36:40 +0200242 with self.subTest(i=1):
243 self.auth.get_project_list.side_effect = [[proj], []]
244 new_name = "new-project-name"
selvi.j0389d9e2023-04-26 12:13:10 +0000245 quotas = {
246 "vnfds": random.SystemRandom().randint(0, 100),
247 "nsds": random.SystemRandom().randint(0, 100),
248 }
garciadeblas4568a372021-03-24 09:19:48 +0100249 self.topic.edit(
250 self.fake_session, pid, {"name": new_name, "quotas": quotas}
251 )
delacruzramo79e40f42019-10-10 16:36:40 +0200252 _id, content = self.auth.update_project.call_args[0]
253 self.assertEqual(_id, pid, "Wrong project identifier")
254 self.assertEqual(content["_id"], pid, "Wrong project identifier")
255 self.assertEqual(content["_admin"]["created"], now, "Wrong creation time")
garciadeblas4568a372021-03-24 09:19:48 +0100256 self.assertGreater(
257 content["_admin"]["modified"], now, "Wrong modification time"
258 )
delacruzramo79e40f42019-10-10 16:36:40 +0200259 self.assertEqual(content["name"], new_name, "Wrong project name")
260 self.assertEqual(content["quotas"], quotas, "Wrong quotas")
261 with self.subTest(i=2):
262 new_name = "other-project-name"
selvi.j0389d9e2023-04-26 12:13:10 +0000263 quotas = {"baditems": random.SystemRandom().randint(0, 100)}
delacruzramo79e40f42019-10-10 16:36:40 +0200264 self.auth.get_project_list.side_effect = [[proj], []]
265 with self.assertRaises(EngineException, msg="Accepted wrong quotas") as e:
garciadeblas4568a372021-03-24 09:19:48 +0100266 self.topic.edit(
267 self.fake_session, pid, {"name": new_name, "quotas": quotas}
268 )
269 self.assertEqual(
270 e.exception.http_code,
271 HTTPStatus.UNPROCESSABLE_ENTITY,
272 "Wrong HTTP status code",
273 )
274 self.assertIn(
275 "format error at 'quotas' 'additional properties are not allowed ('{}' was unexpected)'".format(
276 "baditems"
277 ),
278 norm(str(e.exception)),
279 "Wrong exception text",
280 )
delacruzramo79e40f42019-10-10 16:36:40 +0200281
282 def test_conflict_on_new(self):
283 with self.subTest(i=1):
284 rollback = []
285 pid = str(uuid4())
garciadeblas4568a372021-03-24 09:19:48 +0100286 with self.assertRaises(
287 EngineException, msg="Accepted uuid as project name"
288 ) as e:
delacruzramo79e40f42019-10-10 16:36:40 +0200289 self.topic.new(rollback, self.fake_session, {"name": pid})
290 self.assertEqual(len(rollback), 0, "Wrong rollback length")
garciadeblas4568a372021-03-24 09:19:48 +0100291 self.assertEqual(
292 e.exception.http_code,
293 HTTPStatus.UNPROCESSABLE_ENTITY,
294 "Wrong HTTP status code",
295 )
296 self.assertIn(
297 "project name '{}' cannot have an uuid format".format(pid),
298 norm(str(e.exception)),
299 "Wrong exception text",
300 )
delacruzramo79e40f42019-10-10 16:36:40 +0200301 with self.subTest(i=2):
302 rollback = []
garciadeblas4568a372021-03-24 09:19:48 +0100303 self.auth.get_project_list.return_value = [
304 {"_id": test_pid, "name": self.test_name}
305 ]
306 with self.assertRaises(
307 EngineException, msg="Accepted existing project name"
308 ) as e:
delacruzramo79e40f42019-10-10 16:36:40 +0200309 self.topic.new(rollback, self.fake_session, {"name": self.test_name})
310 self.assertEqual(len(rollback), 0, "Wrong rollback length")
garciadeblas4568a372021-03-24 09:19:48 +0100311 self.assertEqual(
312 e.exception.http_code, HTTPStatus.CONFLICT, "Wrong HTTP status code"
313 )
314 self.assertIn(
315 "project '{}' exists".format(self.test_name),
316 norm(str(e.exception)),
317 "Wrong exception text",
318 )
delacruzramo79e40f42019-10-10 16:36:40 +0200319
320 def test_conflict_on_edit(self):
321 with self.subTest(i=1):
garciadeblas4568a372021-03-24 09:19:48 +0100322 self.auth.get_project_list.return_value = [
323 {"_id": test_pid, "name": self.test_name}
324 ]
delacruzramo79e40f42019-10-10 16:36:40 +0200325 new_name = str(uuid4())
garciadeblas4568a372021-03-24 09:19:48 +0100326 with self.assertRaises(
327 EngineException, msg="Accepted uuid as project name"
328 ) as e:
delacruzramo79e40f42019-10-10 16:36:40 +0200329 self.topic.edit(self.fake_session, test_pid, {"name": new_name})
garciadeblas4568a372021-03-24 09:19:48 +0100330 self.assertEqual(
331 e.exception.http_code,
332 HTTPStatus.UNPROCESSABLE_ENTITY,
333 "Wrong HTTP status code",
334 )
335 self.assertIn(
336 "project name '{}' cannot have an uuid format".format(new_name),
337 norm(str(e.exception)),
338 "Wrong exception text",
339 )
delacruzramo79e40f42019-10-10 16:36:40 +0200340 with self.subTest(i=2):
341 pid = str(uuid4())
342 self.auth.get_project_list.return_value = [{"_id": pid, "name": "admin"}]
garciadeblas4568a372021-03-24 09:19:48 +0100343 with self.assertRaises(
344 EngineException, msg="Accepted renaming of project 'admin'"
345 ) as e:
delacruzramo79e40f42019-10-10 16:36:40 +0200346 self.topic.edit(self.fake_session, pid, {"name": "new-name"})
garciadeblas4568a372021-03-24 09:19:48 +0100347 self.assertEqual(
348 e.exception.http_code, HTTPStatus.CONFLICT, "Wrong HTTP status code"
349 )
350 self.assertIn(
351 "you cannot rename project 'admin'",
352 norm(str(e.exception)),
353 "Wrong exception text",
354 )
delacruzramo79e40f42019-10-10 16:36:40 +0200355 with self.subTest(i=3):
356 new_name = "new-project-name"
garciadeblas4568a372021-03-24 09:19:48 +0100357 self.auth.get_project_list.side_effect = [
358 [{"_id": test_pid, "name": self.test_name}],
359 [{"_id": str(uuid4()), "name": new_name}],
360 ]
361 with self.assertRaises(
362 EngineException, msg="Accepted existing project name"
363 ) as e:
delacruzramo79e40f42019-10-10 16:36:40 +0200364 self.topic.edit(self.fake_session, pid, {"name": new_name})
garciadeblas4568a372021-03-24 09:19:48 +0100365 self.assertEqual(
366 e.exception.http_code, HTTPStatus.CONFLICT, "Wrong HTTP status code"
367 )
368 self.assertIn(
369 "project '{}' is already used".format(new_name),
370 norm(str(e.exception)),
371 "Wrong exception text",
372 )
delacruzramo79e40f42019-10-10 16:36:40 +0200373
374 def test_delete_project(self):
375 with self.subTest(i=1):
376 pid = str(uuid4())
garciadeblas4568a372021-03-24 09:19:48 +0100377 self.auth.get_project.return_value = {
378 "_id": pid,
379 "name": "other-project-name",
380 }
delacruzramo79e40f42019-10-10 16:36:40 +0200381 self.auth.delete_project.return_value = {"deleted": 1}
382 self.auth.get_user_list.return_value = []
383 self.db.get_list.return_value = []
384 rc = self.topic.delete(self.fake_session, pid)
385 self.assertEqual(rc, {"deleted": 1}, "Wrong project deletion return info")
garciadeblas4568a372021-03-24 09:19:48 +0100386 self.assertEqual(
387 self.auth.get_project.call_args[0][0], pid, "Wrong project identifier"
388 )
389 self.assertEqual(
390 self.auth.delete_project.call_args[0][0],
391 pid,
392 "Wrong project identifier",
393 )
delacruzramo79e40f42019-10-10 16:36:40 +0200394
395 def test_conflict_on_del(self):
396 with self.subTest(i=1):
garciadeblas4568a372021-03-24 09:19:48 +0100397 self.auth.get_project.return_value = {
398 "_id": test_pid,
399 "name": self.test_name,
400 }
401 with self.assertRaises(
402 EngineException, msg="Accepted deletion of own project"
403 ) as e:
delacruzramo79e40f42019-10-10 16:36:40 +0200404 self.topic.delete(self.fake_session, self.test_name)
garciadeblas4568a372021-03-24 09:19:48 +0100405 self.assertEqual(
406 e.exception.http_code, HTTPStatus.CONFLICT, "Wrong HTTP status code"
407 )
408 self.assertIn(
409 "you cannot delete your own project",
410 norm(str(e.exception)),
411 "Wrong exception text",
412 )
delacruzramo79e40f42019-10-10 16:36:40 +0200413 with self.subTest(i=2):
414 self.auth.get_project.return_value = {"_id": str(uuid4()), "name": "admin"}
garciadeblas4568a372021-03-24 09:19:48 +0100415 with self.assertRaises(
416 EngineException, msg="Accepted deletion of project 'admin'"
417 ) as e:
delacruzramo79e40f42019-10-10 16:36:40 +0200418 self.topic.delete(self.fake_session, "admin")
garciadeblas4568a372021-03-24 09:19:48 +0100419 self.assertEqual(
420 e.exception.http_code, HTTPStatus.CONFLICT, "Wrong HTTP status code"
421 )
422 self.assertIn(
423 "you cannot delete project 'admin'",
424 norm(str(e.exception)),
425 "Wrong exception text",
426 )
delacruzramo79e40f42019-10-10 16:36:40 +0200427 with self.subTest(i=3):
428 pid = str(uuid4())
429 name = "other-project-name"
430 self.auth.get_project.return_value = {"_id": pid, "name": name}
garciadeblas4568a372021-03-24 09:19:48 +0100431 self.auth.get_user_list.return_value = [
432 {
433 "_id": str(uuid4()),
434 "username": self.test_name,
435 "project_role_mappings": [{"project": pid, "role": str(uuid4())}],
436 }
437 ]
438 with self.assertRaises(
439 EngineException, msg="Accepted deletion of used project"
440 ) as e:
delacruzramo79e40f42019-10-10 16:36:40 +0200441 self.topic.delete(self.fake_session, pid)
garciadeblas4568a372021-03-24 09:19:48 +0100442 self.assertEqual(
443 e.exception.http_code, HTTPStatus.CONFLICT, "Wrong HTTP status code"
444 )
445 self.assertIn(
446 "project '{}' ({}) is being used by user '{}'".format(
447 name, pid, self.test_name
448 ),
449 norm(str(e.exception)),
450 "Wrong exception text",
451 )
delacruzramo79e40f42019-10-10 16:36:40 +0200452 with self.subTest(i=4):
453 self.auth.get_user_list.return_value = []
garciadeblas4568a372021-03-24 09:19:48 +0100454 self.db.get_list.return_value = [
455 {
456 "_id": str(uuid4()),
457 "id": self.test_name,
458 "_admin": {"projects_read": [pid], "projects_write": []},
459 }
460 ]
461 with self.assertRaises(
462 EngineException, msg="Accepted deletion of used project"
463 ) as e:
delacruzramo79e40f42019-10-10 16:36:40 +0200464 self.topic.delete(self.fake_session, pid)
garciadeblas4568a372021-03-24 09:19:48 +0100465 self.assertEqual(
466 e.exception.http_code, HTTPStatus.CONFLICT, "Wrong HTTP status code"
467 )
468 self.assertIn(
469 "project '{}' ({}) is being used by {} '{}'".format(
470 name, pid, "vnf descriptor", self.test_name
471 ),
472 norm(str(e.exception)),
473 "Wrong exception text",
474 )
delacruzramo79e40f42019-10-10 16:36:40 +0200475
476
477class Test_RoleTopicAuth(TestCase):
delacruzramo79e40f42019-10-10 16:36:40 +0200478 @classmethod
479 def setUpClass(cls):
480 cls.test_name = "test-role-topic"
481 cls.test_operations = ["tokens:get"]
482
483 def setUp(self):
484 self.db = Mock(dbbase.DbBase())
485 self.fs = Mock(fsbase.FsBase())
486 self.msg = Mock(msgbase.MsgBase())
tierno9e87a7f2020-03-23 09:24:10 +0000487 self.auth = Mock(authconn.Authconn(None, None, None))
488 self.auth.role_permissions = self.test_operations
489 self.topic = RoleTopicAuth(self.db, self.fs, self.msg, self.auth)
garciadeblas4568a372021-03-24 09:19:48 +0100490 self.fake_session = {
491 "username": test_name,
492 "project_id": (test_pid,),
493 "method": None,
494 "admin": True,
495 "force": False,
496 "public": False,
497 "allow_show_user_project_role": True,
498 }
tiernod7749582020-05-28 10:41:10 +0000499 self.topic.check_quota = Mock(return_value=None) # skip quota
delacruzramo79e40f42019-10-10 16:36:40 +0200500
501 def test_new_role(self):
502 with self.subTest(i=1):
503 rollback = []
504 rid1 = str(uuid4())
505 perms_in = {"tokens": True}
506 perms_out = {"default": False, "admin": False, "tokens": True}
507 self.auth.get_role_list.return_value = []
508 self.auth.create_role.return_value = rid1
garciadeblas4568a372021-03-24 09:19:48 +0100509 rid2, oid = self.topic.new(
510 rollback,
511 self.fake_session,
512 {"name": self.test_name, "permissions": perms_in},
513 )
delacruzramo79e40f42019-10-10 16:36:40 +0200514 self.assertEqual(len(rollback), 1, "Wrong rollback length")
515 self.assertEqual(rid2, rid1, "Wrong project identifier")
516 content = self.auth.create_role.call_args[0][0]
517 self.assertEqual(content["name"], self.test_name, "Wrong role name")
518 self.assertEqual(content["permissions"], perms_out, "Wrong permissions")
519 self.assertIsNotNone(content["_admin"]["created"], "Wrong creation time")
garciadeblas4568a372021-03-24 09:19:48 +0100520 self.assertEqual(
521 content["_admin"]["modified"],
522 content["_admin"]["created"],
523 "Wrong modification time",
524 )
delacruzramo79e40f42019-10-10 16:36:40 +0200525 with self.subTest(i=2):
526 rollback = []
garciadeblas4568a372021-03-24 09:19:48 +0100527 with self.assertRaises(
528 EngineException, msg="Accepted wrong permissions"
529 ) as e:
530 self.topic.new(
531 rollback,
532 self.fake_session,
533 {"name": "other-role-name", "permissions": {"projects": True}},
534 )
delacruzramo79e40f42019-10-10 16:36:40 +0200535 self.assertEqual(len(rollback), 0, "Wrong rollback length")
garciadeblas4568a372021-03-24 09:19:48 +0100536 self.assertEqual(
537 e.exception.http_code,
538 HTTPStatus.UNPROCESSABLE_ENTITY,
539 "Wrong HTTP status code",
540 )
541 self.assertIn(
542 "invalid permission '{}'".format("projects"),
543 norm(str(e.exception)),
544 "Wrong exception text",
545 )
delacruzramo79e40f42019-10-10 16:36:40 +0200546
547 def test_edit_role(self):
548 now = time()
549 rid = str(uuid4())
garciadeblas4568a372021-03-24 09:19:48 +0100550 role = {
551 "_id": rid,
552 "name": self.test_name,
553 "permissions": {"tokens": True},
554 "_admin": {"created": now, "modified": now},
555 }
delacruzramo79e40f42019-10-10 16:36:40 +0200556 with self.subTest(i=1):
557 self.auth.get_role_list.side_effect = [[role], []]
558 self.auth.get_role.return_value = role
559 new_name = "new-role-name"
560 perms_in = {"tokens": False, "tokens:get": True}
garciadeblas4568a372021-03-24 09:19:48 +0100561 perms_out = {
562 "default": False,
563 "admin": False,
564 "tokens": False,
565 "tokens:get": True,
566 }
567 self.topic.edit(
568 self.fake_session, rid, {"name": new_name, "permissions": perms_in}
569 )
delacruzramo79e40f42019-10-10 16:36:40 +0200570 content = self.auth.update_role.call_args[0][0]
571 self.assertEqual(content["_id"], rid, "Wrong role identifier")
572 self.assertEqual(content["_admin"]["created"], now, "Wrong creation time")
garciadeblas4568a372021-03-24 09:19:48 +0100573 self.assertGreater(
574 content["_admin"]["modified"], now, "Wrong modification time"
575 )
delacruzramo79e40f42019-10-10 16:36:40 +0200576 self.assertEqual(content["name"], new_name, "Wrong role name")
577 self.assertEqual(content["permissions"], perms_out, "Wrong permissions")
578 with self.subTest(i=2):
579 new_name = "other-role-name"
580 perms_in = {"tokens": False, "tokens:post": True}
581 self.auth.get_role_list.side_effect = [[role], []]
garciadeblas4568a372021-03-24 09:19:48 +0100582 with self.assertRaises(
583 EngineException, msg="Accepted wrong permissions"
584 ) as e:
585 self.topic.edit(
586 self.fake_session, rid, {"name": new_name, "permissions": perms_in}
587 )
588 self.assertEqual(
589 e.exception.http_code,
590 HTTPStatus.UNPROCESSABLE_ENTITY,
591 "Wrong HTTP status code",
592 )
593 self.assertIn(
594 "invalid permission '{}'".format("tokens:post"),
595 norm(str(e.exception)),
596 "Wrong exception text",
597 )
delacruzramo79e40f42019-10-10 16:36:40 +0200598
599 def test_delete_role(self):
600 with self.subTest(i=1):
601 rid = str(uuid4())
602 role = {"_id": rid, "name": "other-role-name"}
603 self.auth.get_role_list.return_value = [role]
604 self.auth.get_role.return_value = role
605 self.auth.delete_role.return_value = {"deleted": 1}
606 self.auth.get_user_list.return_value = []
607 rc = self.topic.delete(self.fake_session, rid)
608 self.assertEqual(rc, {"deleted": 1}, "Wrong role deletion return info")
garciadeblas4568a372021-03-24 09:19:48 +0100609 self.assertEqual(
610 self.auth.get_role_list.call_args[0][0]["_id"],
611 rid,
612 "Wrong role identifier",
613 )
614 self.assertEqual(
615 self.auth.get_role.call_args[0][0], rid, "Wrong role identifier"
616 )
617 self.assertEqual(
618 self.auth.delete_role.call_args[0][0], rid, "Wrong role identifier"
619 )
delacruzramo79e40f42019-10-10 16:36:40 +0200620
621 def test_conflict_on_new(self):
622 with self.subTest(i=1):
623 rollback = []
624 rid = str(uuid4())
garciadeblas4568a372021-03-24 09:19:48 +0100625 with self.assertRaises(
626 EngineException, msg="Accepted uuid as role name"
627 ) as e:
delacruzramo79e40f42019-10-10 16:36:40 +0200628 self.topic.new(rollback, self.fake_session, {"name": rid})
629 self.assertEqual(len(rollback), 0, "Wrong rollback length")
garciadeblas4568a372021-03-24 09:19:48 +0100630 self.assertEqual(
631 e.exception.http_code,
632 HTTPStatus.UNPROCESSABLE_ENTITY,
633 "Wrong HTTP status code",
634 )
635 self.assertIn(
636 "role name '{}' cannot have an uuid format".format(rid),
637 norm(str(e.exception)),
638 "Wrong exception text",
639 )
delacruzramo79e40f42019-10-10 16:36:40 +0200640 with self.subTest(i=2):
641 rollback = []
garciadeblas4568a372021-03-24 09:19:48 +0100642 self.auth.get_role_list.return_value = [
643 {"_id": str(uuid4()), "name": self.test_name}
644 ]
645 with self.assertRaises(
646 EngineException, msg="Accepted existing role name"
647 ) as e:
delacruzramo79e40f42019-10-10 16:36:40 +0200648 self.topic.new(rollback, self.fake_session, {"name": self.test_name})
649 self.assertEqual(len(rollback), 0, "Wrong rollback length")
garciadeblas4568a372021-03-24 09:19:48 +0100650 self.assertEqual(
651 e.exception.http_code, HTTPStatus.CONFLICT, "Wrong HTTP status code"
652 )
653 self.assertIn(
654 "role name '{}' exists".format(self.test_name),
655 norm(str(e.exception)),
656 "Wrong exception text",
657 )
delacruzramo79e40f42019-10-10 16:36:40 +0200658
659 def test_conflict_on_edit(self):
660 rid = str(uuid4())
661 with self.subTest(i=1):
garciadeblas4568a372021-03-24 09:19:48 +0100662 self.auth.get_role_list.return_value = [
663 {"_id": rid, "name": self.test_name, "permissions": {}}
664 ]
delacruzramo79e40f42019-10-10 16:36:40 +0200665 new_name = str(uuid4())
garciadeblas4568a372021-03-24 09:19:48 +0100666 with self.assertRaises(
667 EngineException, msg="Accepted uuid as role name"
668 ) as e:
delacruzramo79e40f42019-10-10 16:36:40 +0200669 self.topic.edit(self.fake_session, rid, {"name": new_name})
garciadeblas4568a372021-03-24 09:19:48 +0100670 self.assertEqual(
671 e.exception.http_code,
672 HTTPStatus.UNPROCESSABLE_ENTITY,
673 "Wrong HTTP status code",
674 )
675 self.assertIn(
676 "role name '{}' cannot have an uuid format".format(new_name),
677 norm(str(e.exception)),
678 "Wrong exception text",
679 )
delacruzramo79e40f42019-10-10 16:36:40 +0200680 for i, role_name in enumerate(["system_admin", "project_admin"], start=2):
681 with self.subTest(i=i):
682 rid = str(uuid4())
garciadeblas4568a372021-03-24 09:19:48 +0100683 self.auth.get_role.return_value = {
684 "_id": rid,
685 "name": role_name,
686 "permissions": {},
687 }
688 with self.assertRaises(
689 EngineException,
690 msg="Accepted renaming of role '{}'".format(role_name),
691 ) as e:
delacruzramo79e40f42019-10-10 16:36:40 +0200692 self.topic.edit(self.fake_session, rid, {"name": "new-name"})
garciadeblas4568a372021-03-24 09:19:48 +0100693 self.assertEqual(
694 e.exception.http_code,
695 HTTPStatus.FORBIDDEN,
696 "Wrong HTTP status code",
697 )
698 self.assertIn(
699 "you cannot rename role '{}'".format(role_name),
700 norm(str(e.exception)),
701 "Wrong exception text",
702 )
703 with self.subTest(i=i + 1):
delacruzramo79e40f42019-10-10 16:36:40 +0200704 new_name = "new-role-name"
garciadeblas4568a372021-03-24 09:19:48 +0100705 self.auth.get_role_list.side_effect = [
706 [{"_id": rid, "name": self.test_name, "permissions": {}}],
707 [{"_id": str(uuid4()), "name": new_name, "permissions": {}}],
708 ]
709 self.auth.get_role.return_value = {
710 "_id": rid,
711 "name": self.test_name,
712 "permissions": {},
713 }
714 with self.assertRaises(
715 EngineException, msg="Accepted existing role name"
716 ) as e:
delacruzramo79e40f42019-10-10 16:36:40 +0200717 self.topic.edit(self.fake_session, rid, {"name": new_name})
garciadeblas4568a372021-03-24 09:19:48 +0100718 self.assertEqual(
719 e.exception.http_code, HTTPStatus.CONFLICT, "Wrong HTTP status code"
720 )
721 self.assertIn(
722 "role name '{}' exists".format(new_name),
723 norm(str(e.exception)),
724 "Wrong exception text",
725 )
delacruzramo79e40f42019-10-10 16:36:40 +0200726
727 def test_conflict_on_del(self):
728 for i, role_name in enumerate(["system_admin", "project_admin"], start=1):
729 with self.subTest(i=i):
730 rid = str(uuid4())
731 role = {"_id": rid, "name": role_name}
732 self.auth.get_role_list.return_value = [role]
733 self.auth.get_role.return_value = role
garciadeblas4568a372021-03-24 09:19:48 +0100734 with self.assertRaises(
735 EngineException,
736 msg="Accepted deletion of role '{}'".format(role_name),
737 ) as e:
delacruzramo79e40f42019-10-10 16:36:40 +0200738 self.topic.delete(self.fake_session, rid)
garciadeblas4568a372021-03-24 09:19:48 +0100739 self.assertEqual(
740 e.exception.http_code,
741 HTTPStatus.FORBIDDEN,
742 "Wrong HTTP status code",
743 )
744 self.assertIn(
745 "you cannot delete role '{}'".format(role_name),
746 norm(str(e.exception)),
747 "Wrong exception text",
748 )
749 with self.subTest(i=i + 1):
delacruzramo79e40f42019-10-10 16:36:40 +0200750 rid = str(uuid4())
751 name = "other-role-name"
752 role = {"_id": rid, "name": name}
753 self.auth.get_role_list.return_value = [role]
754 self.auth.get_role.return_value = role
garciadeblas4568a372021-03-24 09:19:48 +0100755 self.auth.get_user_list.return_value = [
756 {
757 "_id": str(uuid4()),
758 "username": self.test_name,
759 "project_role_mappings": [{"project": str(uuid4()), "role": rid}],
760 }
761 ]
762 with self.assertRaises(
763 EngineException, msg="Accepted deletion of used role"
764 ) as e:
delacruzramo79e40f42019-10-10 16:36:40 +0200765 self.topic.delete(self.fake_session, rid)
garciadeblas4568a372021-03-24 09:19:48 +0100766 self.assertEqual(
767 e.exception.http_code, HTTPStatus.CONFLICT, "Wrong HTTP status code"
768 )
769 self.assertIn(
770 "role '{}' ({}) is being used by user '{}'".format(
771 name, rid, self.test_name
772 ),
773 norm(str(e.exception)),
774 "Wrong exception text",
775 )
delacruzramo79e40f42019-10-10 16:36:40 +0200776
777
778class Test_UserTopicAuth(TestCase):
delacruzramo79e40f42019-10-10 16:36:40 +0200779 @classmethod
780 def setUpClass(cls):
781 cls.test_name = "test-user-topic"
garciadeblas6d83f8f2023-06-19 22:34:49 +0200782 cls.password = "Test@123"
delacruzramo79e40f42019-10-10 16:36:40 +0200783
784 def setUp(self):
garciadeblas6d83f8f2023-06-19 22:34:49 +0200785 # self.db = Mock(dbbase.DbBase())
786 self.db = DbMemory()
delacruzramo79e40f42019-10-10 16:36:40 +0200787 self.fs = Mock(fsbase.FsBase())
788 self.msg = Mock(msgbase.MsgBase())
tierno9e87a7f2020-03-23 09:24:10 +0000789 self.auth = Mock(authconn.Authconn(None, None, None))
delacruzramo79e40f42019-10-10 16:36:40 +0200790 self.topic = UserTopicAuth(self.db, self.fs, self.msg, self.auth)
garciadeblas4568a372021-03-24 09:19:48 +0100791 self.fake_session = {
792 "username": test_name,
793 "project_id": (test_pid,),
794 "method": None,
795 "admin": True,
796 "force": False,
797 "public": False,
798 "allow_show_user_project_role": True,
799 }
tiernod7749582020-05-28 10:41:10 +0000800 self.topic.check_quota = Mock(return_value=None) # skip quota
delacruzramo79e40f42019-10-10 16:36:40 +0200801
802 def test_new_user(self):
803 uid1 = str(uuid4())
804 pid = str(uuid4())
805 self.auth.get_user_list.return_value = []
806 self.auth.get_project.return_value = {"_id": pid, "name": "some_project"}
807 self.auth.create_user.return_value = {"_id": uid1, "username": self.test_name}
808 with self.subTest(i=1):
809 rollback = []
810 rid = str(uuid4())
811 self.auth.get_role.return_value = {"_id": rid, "name": "some_role"}
812 prms_in = [{"project": "some_project", "role": "some_role"}]
813 prms_out = [{"project": pid, "role": rid}]
garciadeblas4568a372021-03-24 09:19:48 +0100814 uid2, oid = self.topic.new(
815 rollback,
816 self.fake_session,
817 {
818 "username": self.test_name,
garciadeblas6d83f8f2023-06-19 22:34:49 +0200819 "password": self.password,
garciadeblas4568a372021-03-24 09:19:48 +0100820 "project_role_mappings": prms_in,
821 },
822 )
delacruzramo79e40f42019-10-10 16:36:40 +0200823 self.assertEqual(len(rollback), 1, "Wrong rollback length")
824 self.assertEqual(uid2, uid1, "Wrong project identifier")
825 content = self.auth.create_user.call_args[0][0]
826 self.assertEqual(content["username"], self.test_name, "Wrong project name")
garciadeblas6d83f8f2023-06-19 22:34:49 +0200827 self.assertEqual(content["password"], self.password, "Wrong password")
garciadeblas4568a372021-03-24 09:19:48 +0100828 self.assertEqual(
829 content["project_role_mappings"],
830 prms_out,
831 "Wrong project-role mappings",
832 )
delacruzramo79e40f42019-10-10 16:36:40 +0200833 self.assertIsNotNone(content["_admin"]["created"], "Wrong creation time")
garciadeblas4568a372021-03-24 09:19:48 +0100834 self.assertEqual(
835 content["_admin"]["modified"],
836 content["_admin"]["created"],
837 "Wrong modification time",
838 )
delacruzramo79e40f42019-10-10 16:36:40 +0200839 with self.subTest(i=2):
840 rollback = []
841 def_rid = str(uuid4())
842 def_role = {"_id": def_rid, "name": "project_admin"}
843 self.auth.get_role.return_value = def_role
844 self.auth.get_role_list.return_value = [def_role]
845 prms_out = [{"project": pid, "role": def_rid}]
garciadeblas4568a372021-03-24 09:19:48 +0100846 uid2, oid = self.topic.new(
847 rollback,
848 self.fake_session,
849 {
850 "username": self.test_name,
garciadeblas6d83f8f2023-06-19 22:34:49 +0200851 "password": self.password,
garciadeblas4568a372021-03-24 09:19:48 +0100852 "projects": ["some_project"],
853 },
854 )
delacruzramo79e40f42019-10-10 16:36:40 +0200855 self.assertEqual(len(rollback), 1, "Wrong rollback length")
856 self.assertEqual(uid2, uid1, "Wrong project identifier")
857 content = self.auth.create_user.call_args[0][0]
858 self.assertEqual(content["username"], self.test_name, "Wrong project name")
garciadeblas6d83f8f2023-06-19 22:34:49 +0200859 self.assertEqual(content["password"], self.password, "Wrong password")
garciadeblas4568a372021-03-24 09:19:48 +0100860 self.assertEqual(
861 content["project_role_mappings"],
862 prms_out,
863 "Wrong project-role mappings",
864 )
delacruzramo79e40f42019-10-10 16:36:40 +0200865 self.assertIsNotNone(content["_admin"]["created"], "Wrong creation time")
garciadeblas4568a372021-03-24 09:19:48 +0100866 self.assertEqual(
867 content["_admin"]["modified"],
868 content["_admin"]["created"],
869 "Wrong modification time",
870 )
delacruzramo79e40f42019-10-10 16:36:40 +0200871 with self.subTest(i=3):
872 rollback = []
garciadeblas4568a372021-03-24 09:19:48 +0100873 with self.assertRaises(
874 EngineException, msg="Accepted wrong project-role mappings"
875 ) as e:
876 self.topic.new(
877 rollback,
878 self.fake_session,
879 {
880 "username": "other-project-name",
garciadeblas6d83f8f2023-06-19 22:34:49 +0200881 "password": "Other@pwd1",
garciadeblas4568a372021-03-24 09:19:48 +0100882 "project_role_mappings": [{}],
883 },
884 )
delacruzramo79e40f42019-10-10 16:36:40 +0200885 self.assertEqual(len(rollback), 0, "Wrong rollback length")
garciadeblas4568a372021-03-24 09:19:48 +0100886 self.assertEqual(
887 e.exception.http_code,
888 HTTPStatus.UNPROCESSABLE_ENTITY,
889 "Wrong HTTP status code",
890 )
891 self.assertIn(
892 "format error at '{}' '{}'".format(
893 "project_role_mappings:{}", "'{}' is a required property"
894 ).format(0, "project"),
895 norm(str(e.exception)),
896 "Wrong exception text",
897 )
delacruzramo79e40f42019-10-10 16:36:40 +0200898 with self.subTest(i=4):
899 rollback = []
900 with self.assertRaises(EngineException, msg="Accepted wrong projects") as e:
garciadeblas4568a372021-03-24 09:19:48 +0100901 self.topic.new(
902 rollback,
903 self.fake_session,
904 {
905 "username": "other-project-name",
garciadeblas6d83f8f2023-06-19 22:34:49 +0200906 "password": "Other@pwd1",
garciadeblas4568a372021-03-24 09:19:48 +0100907 "projects": [],
908 },
909 )
delacruzramo79e40f42019-10-10 16:36:40 +0200910 self.assertEqual(len(rollback), 0, "Wrong rollback length")
garciadeblas4568a372021-03-24 09:19:48 +0100911 self.assertEqual(
912 e.exception.http_code,
913 HTTPStatus.UNPROCESSABLE_ENTITY,
914 "Wrong HTTP status code",
915 )
916 self.assertIn(
917 "format error at '{}' '{}'".format(
garciadeblasb2c196a2024-08-07 01:34:22 +0200918 "projects", "{} should be non-empty"
garciadeblas4568a372021-03-24 09:19:48 +0100919 ).format([]),
920 norm(str(e.exception)),
921 "Wrong exception text",
922 )
delacruzramo79e40f42019-10-10 16:36:40 +0200923
924 def test_edit_user(self):
925 now = time()
926 uid = str(uuid4())
927 pid1 = str(uuid4())
928 rid1 = str(uuid4())
Adurti76d4b762024-05-07 06:04:37 +0000929 self.fake_session["user_id"] = uid
37177091c0322024-11-01 08:55:59 +0000930 self.fake_session["admin_show"] = True
garciadeblas4568a372021-03-24 09:19:48 +0100931 prms = [
932 {
933 "project": pid1,
934 "project_name": "project-1",
935 "role": rid1,
936 "role_name": "role-1",
937 }
938 ]
939 user = {
940 "_id": uid,
941 "username": self.test_name,
942 "project_role_mappings": prms,
943 "_admin": {"created": now, "modified": now},
944 }
delacruzramo79e40f42019-10-10 16:36:40 +0200945 with self.subTest(i=1):
946 self.auth.get_user_list.side_effect = [[user], []]
947 self.auth.get_user.return_value = user
948 pid2 = str(uuid4())
949 rid2 = str(uuid4())
garciadeblas4568a372021-03-24 09:19:48 +0100950 self.auth.get_project.side_effect = [
951 {"_id": pid2, "name": "project-2"},
952 {"_id": pid1, "name": "project-1"},
953 ]
954 self.auth.get_role.side_effect = [
955 {"_id": rid2, "name": "role-2"},
956 {"_id": rid1, "name": "role-1"},
957 ]
Adurti76d4b762024-05-07 06:04:37 +0000958
959 role = {
960 "_id": rid1,
961 "name": "role-1",
962 "permissions": {"default": False, "admin": False, "roles": True},
963 }
964 self.db.create("users", user)
965 self.db.create("roles", role)
delacruzramo79e40f42019-10-10 16:36:40 +0200966 new_name = "new-user-name"
garciadeblas6d83f8f2023-06-19 22:34:49 +0200967 new_pasw = "New@pwd1"
delacruzramo79e40f42019-10-10 16:36:40 +0200968 add_prms = [{"project": pid2, "role": rid2}]
969 rem_prms = [{"project": pid1, "role": rid1}]
garciadeblas4568a372021-03-24 09:19:48 +0100970 self.topic.edit(
971 self.fake_session,
972 uid,
973 {
974 "username": new_name,
975 "password": new_pasw,
976 "add_project_role_mappings": add_prms,
977 "remove_project_role_mappings": rem_prms,
978 },
979 )
delacruzramo79e40f42019-10-10 16:36:40 +0200980 content = self.auth.update_user.call_args[0][0]
981 self.assertEqual(content["_id"], uid, "Wrong user identifier")
982 self.assertEqual(content["username"], new_name, "Wrong user name")
983 self.assertEqual(content["password"], new_pasw, "Wrong user password")
garciadeblas4568a372021-03-24 09:19:48 +0100984 self.assertEqual(
985 content["add_project_role_mappings"],
986 add_prms,
987 "Wrong project-role mappings to add",
988 )
989 self.assertEqual(
990 content["remove_project_role_mappings"],
991 prms,
992 "Wrong project-role mappings to remove",
993 )
delacruzramo79e40f42019-10-10 16:36:40 +0200994 with self.subTest(i=2):
995 new_name = "other-user-name"
996 new_prms = [{}]
997 self.auth.get_role_list.side_effect = [[user], []]
Frank Brydendeba68e2020-07-27 13:55:11 +0000998 self.auth.get_user_list.side_effect = [[user]]
garciadeblas4568a372021-03-24 09:19:48 +0100999 with self.assertRaises(
1000 EngineException, msg="Accepted wrong project-role mappings"
1001 ) as e:
1002 self.topic.edit(
1003 self.fake_session,
1004 uid,
1005 {"username": new_name, "project_role_mappings": new_prms},
1006 )
1007 self.assertEqual(
1008 e.exception.http_code,
1009 HTTPStatus.UNPROCESSABLE_ENTITY,
1010 "Wrong HTTP status code",
1011 )
1012 self.assertIn(
1013 "format error at '{}' '{}'".format(
1014 "project_role_mappings:{}", "'{}' is a required property"
1015 ).format(0, "project"),
1016 norm(str(e.exception)),
1017 "Wrong exception text",
1018 )
selvi.ja9a1fc82022-04-04 06:54:30 +00001019 with self.subTest(i=3):
1020 self.auth.get_user_list.side_effect = [[user], []]
1021 self.auth.get_user.return_value = user
garciadeblas6d83f8f2023-06-19 22:34:49 +02001022 old_password = self.password
1023 new_pasw = "New@pwd1"
selvi.ja9a1fc82022-04-04 06:54:30 +00001024 self.topic.edit(
1025 self.fake_session,
1026 uid,
1027 {
1028 "old_password": old_password,
1029 "password": new_pasw,
1030 },
1031 )
1032 content = self.auth.update_user.call_args[0][0]
garciadeblasf2af4a12023-01-24 16:56:54 +01001033 self.assertEqual(
1034 content["old_password"], old_password, "Wrong old password"
1035 )
selvi.ja9a1fc82022-04-04 06:54:30 +00001036 self.assertEqual(content["password"], new_pasw, "Wrong user password")
delacruzramo79e40f42019-10-10 16:36:40 +02001037
1038 def test_delete_user(self):
1039 with self.subTest(i=1):
1040 uid = str(uuid4())
1041 self.fake_session["username"] = self.test_name
garciadeblas4568a372021-03-24 09:19:48 +01001042 user = user = {
1043 "_id": uid,
1044 "username": "other-user-name",
1045 "project_role_mappings": [],
1046 }
delacruzramo79e40f42019-10-10 16:36:40 +02001047 self.auth.get_user.return_value = user
1048 self.auth.delete_user.return_value = {"deleted": 1}
1049 rc = self.topic.delete(self.fake_session, uid)
1050 self.assertEqual(rc, {"deleted": 1}, "Wrong user deletion return info")
garciadeblas4568a372021-03-24 09:19:48 +01001051 self.assertEqual(
1052 self.auth.get_user.call_args[0][0], uid, "Wrong user identifier"
1053 )
1054 self.assertEqual(
1055 self.auth.delete_user.call_args[0][0], uid, "Wrong user identifier"
1056 )
delacruzramo79e40f42019-10-10 16:36:40 +02001057
1058 def test_conflict_on_new(self):
1059 with self.subTest(i=1):
1060 rollback = []
1061 uid = str(uuid4())
garciadeblas4568a372021-03-24 09:19:48 +01001062 with self.assertRaises(
1063 EngineException, msg="Accepted uuid as username"
1064 ) as e:
1065 self.topic.new(
1066 rollback,
1067 self.fake_session,
1068 {
1069 "username": uid,
garciadeblas6d83f8f2023-06-19 22:34:49 +02001070 "password": self.password,
garciadeblas4568a372021-03-24 09:19:48 +01001071 "projects": [test_pid],
1072 },
1073 )
delacruzramo79e40f42019-10-10 16:36:40 +02001074 self.assertEqual(len(rollback), 0, "Wrong rollback length")
garciadeblas4568a372021-03-24 09:19:48 +01001075 self.assertEqual(
1076 e.exception.http_code,
1077 HTTPStatus.UNPROCESSABLE_ENTITY,
1078 "Wrong HTTP status code",
1079 )
1080 self.assertIn(
1081 "username '{}' cannot have a uuid format".format(uid),
1082 norm(str(e.exception)),
1083 "Wrong exception text",
1084 )
delacruzramo79e40f42019-10-10 16:36:40 +02001085 with self.subTest(i=2):
1086 rollback = []
garciadeblas4568a372021-03-24 09:19:48 +01001087 self.auth.get_user_list.return_value = [
1088 {"_id": str(uuid4()), "username": self.test_name}
1089 ]
1090 with self.assertRaises(
1091 EngineException, msg="Accepted existing username"
1092 ) as e:
1093 self.topic.new(
1094 rollback,
1095 self.fake_session,
1096 {
1097 "username": self.test_name,
garciadeblas6d83f8f2023-06-19 22:34:49 +02001098 "password": self.password,
garciadeblas4568a372021-03-24 09:19:48 +01001099 "projects": [test_pid],
1100 },
1101 )
delacruzramo79e40f42019-10-10 16:36:40 +02001102 self.assertEqual(len(rollback), 0, "Wrong rollback length")
garciadeblas4568a372021-03-24 09:19:48 +01001103 self.assertEqual(
1104 e.exception.http_code, HTTPStatus.CONFLICT, "Wrong HTTP status code"
1105 )
1106 self.assertIn(
1107 "username '{}' is already used".format(self.test_name),
1108 norm(str(e.exception)),
1109 "Wrong exception text",
1110 )
delacruzramo79e40f42019-10-10 16:36:40 +02001111 with self.subTest(i=3):
1112 rollback = []
1113 self.auth.get_user_list.return_value = []
1114 self.auth.get_role_list.side_effect = [[], []]
garciadeblas4568a372021-03-24 09:19:48 +01001115 with self.assertRaises(
1116 AuthconnNotFoundException, msg="Accepted user without default role"
1117 ) as e:
1118 self.topic.new(
1119 rollback,
1120 self.fake_session,
1121 {
1122 "username": self.test_name,
garciadeblas6d83f8f2023-06-19 22:34:49 +02001123 "password": self.password,
garciadeblas4568a372021-03-24 09:19:48 +01001124 "projects": [str(uuid4())],
1125 },
1126 )
delacruzramo79e40f42019-10-10 16:36:40 +02001127 self.assertEqual(len(rollback), 0, "Wrong rollback length")
garciadeblas4568a372021-03-24 09:19:48 +01001128 self.assertEqual(
1129 e.exception.http_code, HTTPStatus.NOT_FOUND, "Wrong HTTP status code"
1130 )
1131 self.assertIn(
1132 "can't find default role for user '{}'".format(self.test_name),
1133 norm(str(e.exception)),
1134 "Wrong exception text",
1135 )
delacruzramo79e40f42019-10-10 16:36:40 +02001136
1137 def test_conflict_on_edit(self):
1138 uid = str(uuid4())
1139 with self.subTest(i=1):
garciadeblas4568a372021-03-24 09:19:48 +01001140 self.auth.get_user_list.return_value = [
1141 {"_id": uid, "username": self.test_name}
1142 ]
delacruzramo79e40f42019-10-10 16:36:40 +02001143 new_name = str(uuid4())
garciadeblas4568a372021-03-24 09:19:48 +01001144 with self.assertRaises(
1145 EngineException, msg="Accepted uuid as username"
1146 ) as e:
delacruzramo79e40f42019-10-10 16:36:40 +02001147 self.topic.edit(self.fake_session, uid, {"username": new_name})
garciadeblas4568a372021-03-24 09:19:48 +01001148 self.assertEqual(
1149 e.exception.http_code,
1150 HTTPStatus.UNPROCESSABLE_ENTITY,
1151 "Wrong HTTP status code",
1152 )
1153 self.assertIn(
1154 "username '{}' cannot have an uuid format".format(new_name),
1155 norm(str(e.exception)),
1156 "Wrong exception text",
1157 )
delacruzramo79e40f42019-10-10 16:36:40 +02001158 with self.subTest(i=2):
garciadeblas4568a372021-03-24 09:19:48 +01001159 self.auth.get_user_list.return_value = [
1160 {"_id": uid, "username": self.test_name}
1161 ]
delacruzramo79e40f42019-10-10 16:36:40 +02001162 self.auth.get_role_list.side_effect = [[], []]
garciadeblas4568a372021-03-24 09:19:48 +01001163 with self.assertRaises(
1164 AuthconnNotFoundException, msg="Accepted user without default role"
1165 ) as e:
delacruzramo79e40f42019-10-10 16:36:40 +02001166 self.topic.edit(self.fake_session, uid, {"projects": [str(uuid4())]})
garciadeblas4568a372021-03-24 09:19:48 +01001167 self.assertEqual(
1168 e.exception.http_code, HTTPStatus.NOT_FOUND, "Wrong HTTP status code"
1169 )
1170 self.assertIn(
1171 "can't find a default role for user '{}'".format(self.test_name),
1172 norm(str(e.exception)),
1173 "Wrong exception text",
1174 )
delacruzramo79e40f42019-10-10 16:36:40 +02001175 with self.subTest(i=3):
1176 admin_uid = str(uuid4())
garciadeblas4568a372021-03-24 09:19:48 +01001177 self.auth.get_user_list.return_value = [
1178 {"_id": admin_uid, "username": "admin"}
1179 ]
1180 with self.assertRaises(
1181 EngineException,
1182 msg="Accepted removing system_admin role from admin user",
1183 ) as e:
1184 self.topic.edit(
1185 self.fake_session,
1186 admin_uid,
1187 {
1188 "remove_project_role_mappings": [
1189 {"project": "admin", "role": "system_admin"}
1190 ]
1191 },
1192 )
1193 self.assertEqual(
1194 e.exception.http_code, HTTPStatus.FORBIDDEN, "Wrong HTTP status code"
1195 )
1196 self.assertIn(
1197 "you cannot remove system_admin role from admin user",
1198 norm(str(e.exception)),
1199 "Wrong exception text",
1200 )
delacruzramo79e40f42019-10-10 16:36:40 +02001201 with self.subTest(i=4):
1202 new_name = "new-user-name"
garciadeblas4568a372021-03-24 09:19:48 +01001203 self.auth.get_user_list.side_effect = [
1204 [{"_id": uid, "name": self.test_name}],
1205 [{"_id": str(uuid4()), "name": new_name}],
1206 ]
1207 with self.assertRaises(
1208 EngineException, msg="Accepted existing username"
1209 ) as e:
delacruzramo79e40f42019-10-10 16:36:40 +02001210 self.topic.edit(self.fake_session, uid, {"username": new_name})
garciadeblas4568a372021-03-24 09:19:48 +01001211 self.assertEqual(
1212 e.exception.http_code, HTTPStatus.CONFLICT, "Wrong HTTP status code"
1213 )
1214 self.assertIn(
1215 "username '{}' is already used".format(new_name),
1216 norm(str(e.exception)),
1217 "Wrong exception text",
1218 )
delacruzramo79e40f42019-10-10 16:36:40 +02001219
1220 def test_conflict_on_del(self):
1221 with self.subTest(i=1):
1222 uid = str(uuid4())
1223 self.fake_session["username"] = self.test_name
garciadeblas4568a372021-03-24 09:19:48 +01001224 user = user = {
1225 "_id": uid,
1226 "username": self.test_name,
1227 "project_role_mappings": [],
1228 }
delacruzramo79e40f42019-10-10 16:36:40 +02001229 self.auth.get_user.return_value = user
garciadeblas4568a372021-03-24 09:19:48 +01001230 with self.assertRaises(
1231 EngineException, msg="Accepted deletion of own user"
1232 ) as e:
delacruzramo79e40f42019-10-10 16:36:40 +02001233 self.topic.delete(self.fake_session, uid)
garciadeblas4568a372021-03-24 09:19:48 +01001234 self.assertEqual(
1235 e.exception.http_code, HTTPStatus.CONFLICT, "Wrong HTTP status code"
1236 )
1237 self.assertIn(
1238 "you cannot delete your own login user",
1239 norm(str(e.exception)),
1240 "Wrong exception text",
1241 )
delacruzramo79e40f42019-10-10 16:36:40 +02001242
garciadeblas6d83f8f2023-06-19 22:34:49 +02001243 def test_user_management(self):
1244 self.config = {
1245 "user_management": True,
1246 "pwd_expire_days": 30,
1247 "max_pwd_attempt": 5,
1248 "account_expire_days": 90,
1249 "version": "dev",
1250 "deviceVendor": "test",
1251 "deviceProduct": "test",
1252 }
1253 self.permissions = {"admin": True, "default": True}
1254 now = time()
1255 rid = str(uuid4())
1256 role = {
1257 "_id": rid,
1258 "name": self.test_name,
1259 "permissions": self.permissions,
1260 "_admin": {"created": now, "modified": now},
1261 }
1262 self.db.create("roles", role)
1263 admin_user = {
1264 "_id": "72cd0cd6-e8e2-482c-9bc2-15b413bb8500",
1265 "username": "admin",
1266 "password": "bf0d9f988ad9b404464cf8c8749b298209b05fd404119bae0c11e247efbbc4cb",
1267 "_admin": {
1268 "created": 1663058370.7721832,
1269 "modified": 1663681183.5651639,
1270 "salt": "37587e7e0c2f4dbfb9416f3fb5543e2b",
1271 "last_token_time": 1666876472.2962265,
1272 "user_status": "always-active",
1273 "retry_count": 0,
1274 },
1275 "project_role_mappings": [
1276 {"project": "a595ce4e-09dc-4b24-9d6f-e723830bc66b", "role": rid}
1277 ],
1278 }
1279 self.db.create("users", admin_user)
1280 with self.subTest(i=1):
1281 self.user_create = AuthconnInternal(self.config, self.db, self.permissions)
1282 user_info = {"username": "user_mgmt_true", "password": "Test@123"}
1283 self.user_create.create_user(user_info)
1284 user = self.db.get_one("users", {"username": user_info["username"]})
1285 self.assertEqual(user["username"], user_info["username"], "Wrong user name")
1286 self.assertEqual(
1287 user["_admin"]["user_status"], "active", "User status is unknown"
1288 )
1289 self.assertIn("password_expire_time", user["_admin"], "Key is not there")
1290 self.assertIn("account_expire_time", user["_admin"], "Key is not there")
1291 with self.subTest(i=2):
1292 self.user_update = AuthconnInternal(self.config, self.db, self.permissions)
1293 locked_user = {
1294 "username": "user_lock",
1295 "password": "c94ba8cfe81985cf5c84dff16d5bac95814ab17e44a8871755eb4cf3a27b7d3d",
1296 "_admin": {
1297 "created": 1667207552.2191198,
1298 "modified": 1667207552.2191815,
1299 "salt": "560a5d51b1d64bb4b9cae0ccff3f1102",
1300 "user_status": "locked",
1301 "password_expire_time": 1667207552.2191815,
Adurti0c9b0102023-11-08 11:16:32 +00001302 "account_expire_time": now + 60,
garciadeblas6d83f8f2023-06-19 22:34:49 +02001303 "retry_count": 5,
1304 "last_token_time": 1667207552.2191815,
1305 },
1306 "_id": "73bbbb71-ed38-4b79-9f58-ece19e7e32d6",
1307 }
1308 self.db.create("users", locked_user)
1309 user_info = {
1310 "_id": "73bbbb71-ed38-4b79-9f58-ece19e7e32d6",
1311 "system_admin_id": "72cd0cd6-e8e2-482c-9bc2-15b413bb8500",
1312 "unlock": True,
1313 }
1314 self.assertEqual(
1315 locked_user["_admin"]["user_status"], "locked", "User status is unknown"
1316 )
1317 self.user_update.update_user(user_info)
1318 user = self.db.get_one("users", {"username": locked_user["username"]})
1319 self.assertEqual(
1320 user["username"], locked_user["username"], "Wrong user name"
1321 )
1322 self.assertEqual(
1323 user["_admin"]["user_status"], "active", "User status is unknown"
1324 )
1325 self.assertEqual(user["_admin"]["retry_count"], 0, "retry_count is unknown")
1326 with self.subTest(i=3):
1327 self.user_update = AuthconnInternal(self.config, self.db, self.permissions)
1328 expired_user = {
1329 "username": "user_expire",
1330 "password": "c94ba8cfe81985cf5c84dff16d5bac95814ab17e44a8871755eb4cf3a27b7d3d",
1331 "_admin": {
1332 "created": 1665602087.601298,
1333 "modified": 1665636442.1245084,
1334 "salt": "560a5d51b1d64bb4b9cae0ccff3f1102",
1335 "user_status": "expired",
1336 "password_expire_time": 1668248628.2191815,
1337 "account_expire_time": 1666952628.2191815,
1338 "retry_count": 0,
1339 "last_token_time": 1666779828.2171815,
1340 },
1341 "_id": "3266430f-8222-407f-b08f-3a242504ab94",
1342 }
1343 self.db.create("users", expired_user)
1344 user_info = {
1345 "_id": "3266430f-8222-407f-b08f-3a242504ab94",
1346 "system_admin_id": "72cd0cd6-e8e2-482c-9bc2-15b413bb8500",
1347 "renew": True,
1348 }
1349 self.assertEqual(
1350 expired_user["_admin"]["user_status"],
1351 "expired",
1352 "User status is unknown",
1353 )
1354 self.user_update.update_user(user_info)
1355 user = self.db.get_one("users", {"username": expired_user["username"]})
1356 self.assertEqual(
1357 user["username"], expired_user["username"], "Wrong user name"
1358 )
1359 self.assertEqual(
1360 user["_admin"]["user_status"], "active", "User status is unknown"
1361 )
1362 self.assertGreater(
1363 user["_admin"]["account_expire_time"],
1364 expired_user["_admin"]["account_expire_time"],
1365 "User expire time is not get extended",
1366 )
1367 with self.subTest(i=4):
1368 self.config.update({"user_management": False})
1369 self.user_create = AuthconnInternal(self.config, self.db, self.permissions)
1370 user_info = {"username": "user_mgmt_false", "password": "Test@123"}
1371 self.user_create.create_user(user_info)
1372 user = self.db.get_one("users", {"username": user_info["username"]})
1373 self.assertEqual(user["username"], user_info["username"], "Wrong user name")
1374 self.assertEqual(
1375 user["_admin"]["user_status"], "active", "User status is unknown"
1376 )
1377 self.assertNotIn("password_expire_time", user["_admin"], "Key is not there")
1378 self.assertNotIn("account_expire_time", user["_admin"], "Key is not there")
1379
delacruzramo79e40f42019-10-10 16:36:40 +02001380
1381class Test_CommonVimWimSdn(TestCase):
delacruzramo79e40f42019-10-10 16:36:40 +02001382 @classmethod
1383 def setUpClass(cls):
garciadeblas4568a372021-03-24 09:19:48 +01001384 cls.test_name = "test-cim-topic" # CIM = Common Infrastructure Manager
delacruzramo79e40f42019-10-10 16:36:40 +02001385
1386 def setUp(self):
1387 self.db = Mock(dbbase.DbBase())
1388 self.fs = Mock(fsbase.FsBase())
1389 self.msg = Mock(msgbase.MsgBase())
tierno9e87a7f2020-03-23 09:24:10 +00001390 self.auth = Mock(authconn.Authconn(None, None, None))
delacruzramo79e40f42019-10-10 16:36:40 +02001391 self.topic = CommonVimWimSdn(self.db, self.fs, self.msg, self.auth)
1392 # Use WIM schemas for testing because they are the simplest
tiernof5f2e3f2020-03-23 14:42:10 +00001393 self.topic._send_msg = Mock()
delacruzramo79e40f42019-10-10 16:36:40 +02001394 self.topic.topic = "wims"
1395 self.topic.schema_new = validation.wim_account_new_schema
1396 self.topic.schema_edit = validation.wim_account_edit_schema
garciadeblas4568a372021-03-24 09:19:48 +01001397 self.fake_session = {
1398 "username": test_name,
1399 "project_id": (test_pid,),
1400 "method": None,
1401 "admin": True,
1402 "force": False,
1403 "public": False,
1404 "allow_show_user_project_role": True,
1405 }
tiernod7749582020-05-28 10:41:10 +00001406 self.topic.check_quota = Mock(return_value=None) # skip quota
delacruzramo79e40f42019-10-10 16:36:40 +02001407
1408 def test_new_cvws(self):
1409 test_url = "http://0.0.0.0:0"
1410 with self.subTest(i=1):
1411 rollback = []
1412 test_type = "fake"
1413 self.db.get_one.return_value = None
1414 self.db.create.side_effect = lambda self, content: content["_id"]
garciadeblas4568a372021-03-24 09:19:48 +01001415 cid, oid = self.topic.new(
1416 rollback,
1417 self.fake_session,
1418 {"name": self.test_name, "wim_url": test_url, "wim_type": test_type},
1419 )
delacruzramo79e40f42019-10-10 16:36:40 +02001420 self.assertEqual(len(rollback), 1, "Wrong rollback length")
1421 args = self.db.create.call_args[0]
1422 content = args[1]
1423 self.assertEqual(args[0], self.topic.topic, "Wrong topic")
1424 self.assertEqual(content["_id"], cid, "Wrong CIM identifier")
1425 self.assertEqual(content["name"], self.test_name, "Wrong CIM name")
1426 self.assertEqual(content["wim_url"], test_url, "Wrong URL")
1427 self.assertEqual(content["wim_type"], test_type, "Wrong CIM type")
1428 self.assertEqual(content["schema_version"], "1.11", "Wrong schema version")
1429 self.assertEqual(content["op_id"], oid, "Wrong operation identifier")
1430 self.assertIsNotNone(content["_admin"]["created"], "Wrong creation time")
garciadeblas4568a372021-03-24 09:19:48 +01001431 self.assertEqual(
1432 content["_admin"]["modified"],
1433 content["_admin"]["created"],
1434 "Wrong modification time",
1435 )
1436 self.assertEqual(
1437 content["_admin"]["operationalState"],
1438 "PROCESSING",
1439 "Wrong operational state",
1440 )
1441 self.assertEqual(
1442 content["_admin"]["projects_read"],
1443 [test_pid],
1444 "Wrong read-only projects",
1445 )
1446 self.assertEqual(
1447 content["_admin"]["projects_write"],
1448 [test_pid],
1449 "Wrong read/write projects",
1450 )
1451 self.assertIsNone(
1452 content["_admin"]["current_operation"], "Wrong current operation"
1453 )
1454 self.assertEqual(
1455 len(content["_admin"]["operations"]), 1, "Wrong number of operations"
1456 )
delacruzramo79e40f42019-10-10 16:36:40 +02001457 operation = content["_admin"]["operations"][0]
garciadeblas4568a372021-03-24 09:19:48 +01001458 self.assertEqual(
1459 operation["lcmOperationType"], "create", "Wrong operation type"
1460 )
1461 self.assertEqual(
1462 operation["operationState"], "PROCESSING", "Wrong operation state"
1463 )
1464 self.assertGreater(
1465 operation["startTime"],
1466 content["_admin"]["created"],
1467 "Wrong operation start time",
1468 )
1469 self.assertGreater(
1470 operation["statusEnteredTime"],
1471 content["_admin"]["created"],
1472 "Wrong operation status enter time",
1473 )
1474 self.assertEqual(
1475 operation["detailed-status"], "", "Wrong operation detailed status info"
1476 )
1477 self.assertIsNone(
1478 operation["operationParams"], "Wrong operation parameters"
1479 )
tiernob3d0a0e2019-11-13 15:57:51 +00001480 # This test is disabled. From Feature 8030 we admit all WIM/SDN types
1481 # with self.subTest(i=2):
1482 # rollback = []
1483 # test_type = "bad_type"
1484 # with self.assertRaises(EngineException, msg="Accepted wrong CIM type") as e:
1485 # self.topic.new(rollback, self.fake_session,
1486 # {"name": self.test_name, "wim_url": test_url, "wim_type": test_type})
1487 # self.assertEqual(len(rollback), 0, "Wrong rollback length")
1488 # self.assertEqual(e.exception.http_code, HTTPStatus.UNPROCESSABLE_ENTITY, "Wrong HTTP status code")
1489 # self.assertIn("format error at '{}' '{}".format("wim_type", "'{}' is not one of {}").format(test_type,""),
1490 # norm(str(e.exception)), "Wrong exception text")
delacruzramo79e40f42019-10-10 16:36:40 +02001491
1492 def test_conflict_on_new(self):
1493 with self.subTest(i=1):
1494 rollback = []
1495 test_url = "http://0.0.0.0:0"
1496 test_type = "fake"
1497 self.db.get_one.return_value = {"_id": str(uuid4()), "name": self.test_name}
garciadeblas4568a372021-03-24 09:19:48 +01001498 with self.assertRaises(
1499 EngineException, msg="Accepted existing CIM name"
1500 ) as e:
1501 self.topic.new(
1502 rollback,
1503 self.fake_session,
1504 {
1505 "name": self.test_name,
1506 "wim_url": test_url,
1507 "wim_type": test_type,
1508 },
1509 )
delacruzramo79e40f42019-10-10 16:36:40 +02001510 self.assertEqual(len(rollback), 0, "Wrong rollback length")
garciadeblas4568a372021-03-24 09:19:48 +01001511 self.assertEqual(
1512 e.exception.http_code, HTTPStatus.CONFLICT, "Wrong HTTP status code"
1513 )
1514 self.assertIn(
1515 "name '{}' already exists for {}".format(
1516 self.test_name, self.topic.topic
1517 ),
1518 norm(str(e.exception)),
1519 "Wrong exception text",
1520 )
delacruzramo79e40f42019-10-10 16:36:40 +02001521
1522 def test_edit_cvws(self):
1523 now = time()
1524 cid = str(uuid4())
1525 test_url = "http://0.0.0.0:0"
1526 test_type = "fake"
garciadeblas4568a372021-03-24 09:19:48 +01001527 cvws = {
1528 "_id": cid,
1529 "name": self.test_name,
1530 "wim_url": test_url,
1531 "wim_type": test_type,
1532 "_admin": {
1533 "created": now,
1534 "modified": now,
1535 "operations": [{"lcmOperationType": "create"}],
1536 },
1537 }
delacruzramo79e40f42019-10-10 16:36:40 +02001538 with self.subTest(i=1):
1539 new_name = "new-cim-name"
1540 new_url = "https://1.1.1.1:1"
1541 new_type = "onos"
1542 self.db.get_one.side_effect = [cvws, None]
1543 self.db.replace.return_value = {"updated": 1}
1544 # self.db.encrypt.side_effect = [b64str(), b64str()]
garciadeblas4568a372021-03-24 09:19:48 +01001545 self.topic.edit(
1546 self.fake_session,
1547 cid,
1548 {"name": new_name, "wim_url": new_url, "wim_type": new_type},
1549 )
delacruzramo79e40f42019-10-10 16:36:40 +02001550 args = self.db.replace.call_args[0]
1551 content = args[2]
1552 self.assertEqual(args[0], self.topic.topic, "Wrong topic")
1553 self.assertEqual(args[1], cid, "Wrong CIM identifier")
1554 self.assertEqual(content["_id"], cid, "Wrong CIM identifier")
1555 self.assertEqual(content["name"], new_name, "Wrong CIM name")
1556 self.assertEqual(content["wim_type"], new_type, "Wrong CIM type")
1557 self.assertEqual(content["wim_url"], new_url, "Wrong URL")
1558 self.assertEqual(content["_admin"]["created"], now, "Wrong creation time")
garciadeblas4568a372021-03-24 09:19:48 +01001559 self.assertGreater(
1560 content["_admin"]["modified"],
1561 content["_admin"]["created"],
1562 "Wrong modification time",
1563 )
1564 self.assertEqual(
1565 len(content["_admin"]["operations"]), 2, "Wrong number of operations"
1566 )
delacruzramo79e40f42019-10-10 16:36:40 +02001567 operation = content["_admin"]["operations"][1]
garciadeblas4568a372021-03-24 09:19:48 +01001568 self.assertEqual(
1569 operation["lcmOperationType"], "edit", "Wrong operation type"
1570 )
1571 self.assertEqual(
1572 operation["operationState"], "PROCESSING", "Wrong operation state"
1573 )
1574 self.assertGreater(
1575 operation["startTime"],
1576 content["_admin"]["modified"],
1577 "Wrong operation start time",
1578 )
1579 self.assertGreater(
1580 operation["statusEnteredTime"],
1581 content["_admin"]["modified"],
1582 "Wrong operation status enter time",
1583 )
1584 self.assertEqual(
1585 operation["detailed-status"], "", "Wrong operation detailed status info"
1586 )
1587 self.assertIsNone(
1588 operation["operationParams"], "Wrong operation parameters"
1589 )
delacruzramo79e40f42019-10-10 16:36:40 +02001590 with self.subTest(i=2):
Frank Brydendeba68e2020-07-27 13:55:11 +00001591 self.db.get_one.side_effect = [cvws]
delacruzramo79e40f42019-10-10 16:36:40 +02001592 with self.assertRaises(EngineException, msg="Accepted wrong property") as e:
garciadeblas4568a372021-03-24 09:19:48 +01001593 self.topic.edit(
1594 self.fake_session,
1595 str(uuid4()),
1596 {"name": "new-name", "extra_prop": "anything"},
1597 )
1598 self.assertEqual(
1599 e.exception.http_code,
1600 HTTPStatus.UNPROCESSABLE_ENTITY,
1601 "Wrong HTTP status code",
1602 )
1603 self.assertIn(
1604 "format error '{}'".format(
1605 "additional properties are not allowed ('{}' was unexpected)"
1606 ).format("extra_prop"),
1607 norm(str(e.exception)),
1608 "Wrong exception text",
1609 )
delacruzramo79e40f42019-10-10 16:36:40 +02001610
1611 def test_conflict_on_edit(self):
1612 with self.subTest(i=1):
1613 cid = str(uuid4())
1614 new_name = "new-cim-name"
garciadeblas4568a372021-03-24 09:19:48 +01001615 self.db.get_one.side_effect = [
1616 {"_id": cid, "name": self.test_name},
1617 {"_id": str(uuid4()), "name": new_name},
1618 ]
1619 with self.assertRaises(
1620 EngineException, msg="Accepted existing CIM name"
1621 ) as e:
delacruzramo79e40f42019-10-10 16:36:40 +02001622 self.topic.edit(self.fake_session, cid, {"name": new_name})
garciadeblas4568a372021-03-24 09:19:48 +01001623 self.assertEqual(
1624 e.exception.http_code, HTTPStatus.CONFLICT, "Wrong HTTP status code"
1625 )
1626 self.assertIn(
1627 "name '{}' already exists for {}".format(new_name, self.topic.topic),
1628 norm(str(e.exception)),
1629 "Wrong exception text",
1630 )
delacruzramo79e40f42019-10-10 16:36:40 +02001631
1632 def test_delete_cvws(self):
1633 cid = str(uuid4())
1634 ro_pid = str(uuid4())
1635 rw_pid = str(uuid4())
1636 cvws = {"_id": cid, "name": self.test_name}
delacruzramo35c998b2019-11-21 11:09:16 +01001637 self.db.get_list.return_value = []
delacruzramo79e40f42019-10-10 16:36:40 +02001638 with self.subTest(i=1):
garciadeblas4568a372021-03-24 09:19:48 +01001639 cvws["_admin"] = {
1640 "projects_read": [test_pid, ro_pid, rw_pid],
1641 "projects_write": [test_pid, rw_pid],
1642 }
delacruzramo79e40f42019-10-10 16:36:40 +02001643 self.db.get_one.return_value = cvws
1644 oid = self.topic.delete(self.fake_session, cid)
1645 self.assertIsNone(oid, "Wrong operation identifier")
garciadeblas4568a372021-03-24 09:19:48 +01001646 self.assertEqual(
1647 self.db.get_one.call_args[0][0], self.topic.topic, "Wrong topic"
1648 )
1649 self.assertEqual(
1650 self.db.get_one.call_args[0][1]["_id"], cid, "Wrong CIM identifier"
1651 )
1652 self.assertEqual(
1653 self.db.set_one.call_args[0][0], self.topic.topic, "Wrong topic"
1654 )
1655 self.assertEqual(
1656 self.db.set_one.call_args[0][1]["_id"], cid, "Wrong CIM identifier"
1657 )
1658 self.assertEqual(
1659 self.db.set_one.call_args[1]["update_dict"],
1660 None,
1661 "Wrong read-only projects update",
1662 )
1663 self.assertEqual(
1664 self.db.set_one.call_args[1]["pull_list"],
1665 {
1666 "_admin.projects_read": (test_pid,),
1667 "_admin.projects_write": (test_pid,),
1668 },
1669 "Wrong read/write projects update",
1670 )
tiernof5f2e3f2020-03-23 14:42:10 +00001671 self.topic._send_msg.assert_not_called()
delacruzramo35c998b2019-11-21 11:09:16 +01001672 with self.subTest(i=2):
delacruzramo79e40f42019-10-10 16:36:40 +02001673 now = time()
garciadeblas4568a372021-03-24 09:19:48 +01001674 cvws["_admin"] = {
1675 "projects_read": [test_pid],
1676 "projects_write": [test_pid],
1677 "operations": [],
1678 }
delacruzramo79e40f42019-10-10 16:36:40 +02001679 self.db.get_one.return_value = cvws
1680 oid = self.topic.delete(self.fake_session, cid)
garciadeblas4568a372021-03-24 09:19:48 +01001681 self.assertEqual(oid, cid + ":0", "Wrong operation identifier")
1682 self.assertEqual(
1683 self.db.get_one.call_args[0][0], self.topic.topic, "Wrong topic"
1684 )
1685 self.assertEqual(
1686 self.db.get_one.call_args[0][1]["_id"], cid, "Wrong CIM identifier"
1687 )
1688 self.assertEqual(
1689 self.db.set_one.call_args[0][0], self.topic.topic, "Wrong topic"
1690 )
1691 self.assertEqual(
1692 self.db.set_one.call_args[0][1]["_id"], cid, "Wrong user identifier"
1693 )
1694 self.assertEqual(
1695 self.db.set_one.call_args[1]["update_dict"],
1696 {"_admin.to_delete": True},
1697 "Wrong _admin.to_delete update",
1698 )
delacruzramo79e40f42019-10-10 16:36:40 +02001699 operation = self.db.set_one.call_args[1]["push"]["_admin.operations"]
garciadeblas4568a372021-03-24 09:19:48 +01001700 self.assertEqual(
1701 operation["lcmOperationType"], "delete", "Wrong operation type"
1702 )
1703 self.assertEqual(
1704 operation["operationState"], "PROCESSING", "Wrong operation state"
1705 )
1706 self.assertEqual(
1707 operation["detailed-status"], "", "Wrong operation detailed status"
1708 )
1709 self.assertIsNone(
1710 operation["operationParams"], "Wrong operation parameters"
1711 )
1712 self.assertGreater(
1713 operation["startTime"], now, "Wrong operation start time"
1714 )
1715 self.assertGreater(
1716 operation["statusEnteredTime"], now, "Wrong operation status enter time"
1717 )
1718 self.topic._send_msg.assert_called_once_with(
1719 "delete", {"_id": cid, "op_id": cid + ":0"}, not_send_msg=None
1720 )
delacruzramo79e40f42019-10-10 16:36:40 +02001721 with self.subTest(i=3):
garciadeblas4568a372021-03-24 09:19:48 +01001722 cvws["_admin"] = {
1723 "projects_read": [],
1724 "projects_write": [],
1725 "operations": [],
1726 }
delacruzramo79e40f42019-10-10 16:36:40 +02001727 self.db.get_one.return_value = cvws
tiernof5f2e3f2020-03-23 14:42:10 +00001728 self.topic._send_msg.reset_mock()
1729 self.db.get_one.reset_mock()
1730 self.db.del_one.reset_mock()
garciadeblas4568a372021-03-24 09:19:48 +01001731 self.fake_session["force"] = True # to force deletion
1732 self.fake_session["admin"] = True # to force deletion
1733 self.fake_session["project_id"] = [] # to force deletion
delacruzramo79e40f42019-10-10 16:36:40 +02001734 oid = self.topic.delete(self.fake_session, cid)
1735 self.assertIsNone(oid, "Wrong operation identifier")
garciadeblas4568a372021-03-24 09:19:48 +01001736 self.assertEqual(
1737 self.db.get_one.call_args[0][0], self.topic.topic, "Wrong topic"
1738 )
1739 self.assertEqual(
1740 self.db.get_one.call_args[0][1]["_id"], cid, "Wrong CIM identifier"
1741 )
1742 self.assertEqual(
1743 self.db.del_one.call_args[0][0], self.topic.topic, "Wrong topic"
1744 )
1745 self.assertEqual(
1746 self.db.del_one.call_args[0][1]["_id"], cid, "Wrong CIM identifier"
1747 )
1748 self.topic._send_msg.assert_called_once_with(
1749 "deleted", {"_id": cid, "op_id": None}, not_send_msg=None
1750 )
delacruzramo79e40f42019-10-10 16:36:40 +02001751
1752
garciadeblas4568a372021-03-24 09:19:48 +01001753if __name__ == "__main__":
delacruzramo79e40f42019-10-10 16:36:40 +02001754 unittest.main()