diff --git a/backend/SC4SNMP_UI_backend/common/backend_ui_conversions.py b/backend/SC4SNMP_UI_backend/common/backend_ui_conversions.py index ced9a20..cad9d05 100644 --- a/backend/SC4SNMP_UI_backend/common/backend_ui_conversions.py +++ b/backend/SC4SNMP_UI_backend/common/backend_ui_conversions.py @@ -277,6 +277,8 @@ def ui2backend(self, document: dict, **kwargs): raise ValueError("No delete provided") def backend2ui(self, document: dict, **kwargs): + if "inventory_type" not in kwargs.keys(): + raise ValueError("No inventory_type provided") profiles_mongo = document['profiles'] if len(profiles_mongo) > 0: profiles = profiles_mongo.split(";") @@ -284,6 +286,7 @@ def backend2ui(self, document: dict, **kwargs): profiles = [] result = { '_id': str(document["_id"]), + 'inventoryType': kwargs['inventory_type'], 'address': document['address'], 'port': str(document['port']), 'version': document['version'], diff --git a/backend/SC4SNMP_UI_backend/common/inventory_utils.py b/backend/SC4SNMP_UI_backend/common/inventory_utils.py index 2f7e882..58adb30 100644 --- a/backend/SC4SNMP_UI_backend/common/inventory_utils.py +++ b/backend/SC4SNMP_UI_backend/common/inventory_utils.py @@ -12,6 +12,13 @@ class HostConfiguration(Enum): SINGLE = 1 GROUP = 2 +def get_inventory_type(document): + if list(mongo_groups.find({document["address"]: {"$exists": 1}})): + result = "Group" + else: + result = "Host" + return result + def update_profiles_in_inventory(profile_to_search: str, process_record: Callable, **kwargs): """ When profile is edited, then in some cases inventory records using this profile should be updated. @@ -25,7 +32,7 @@ def update_profiles_in_inventory(profile_to_search: str, process_record: Callabl inventory_records = list(mongo_inventory.find({"profiles": {"$regex": f'.*{profile_to_search}.*'}})) for record in inventory_records: record_id = record["_id"] - record_updated = inventory_conversion.backend2ui(record) + record_updated = inventory_conversion.backend2ui(record, inventory_type=None) # inventory_type isn't used index_to_update = record_updated["profiles"].index(profile_to_search) record_updated = process_record(index_to_update, record_updated, kwargs) record_updated = inventory_conversion.ui2backend(record_updated, delete=False) @@ -92,11 +99,15 @@ def _is_host_configured(self, address: str, port: str): def add_single_host(self, address, port, device_object=None, add: bool=True): host_configured, deleted_inventory_record, host_configuration, existing_id_string, group_name = \ self._is_host_configured(address, port) + groups = list(mongo_groups.find({address: {"$exists": True}})) if host_configured: - host_location_message = "as a single host in the inventory" if host_configuration == HostConfiguration.SINGLE else \ + host_location_message = "in the inventory" if host_configuration == HostConfiguration.SINGLE else \ f"in group {group_name}" message = f"Host {address}:{port} already exists {host_location_message}. Record was not added." host_added = False + elif groups: + message = f"There is a group with the same name configured. Record {address} can't be added as a single host." + host_added = False else: if add and device_object is not None: self._mongo_inventory.insert_one(device_object) @@ -130,7 +141,7 @@ def edit_single_host(self, address: str, port: str, host_id: str, device_object= if len(deleted_inventory_record) > 0: self._mongo_inventory.delete_one({"_id": deleted_inventory_record[0]["_id"]}) else: - host_location_message = "as a single host in the inventory" if host_configuration == HostConfiguration.SINGLE else \ + host_location_message = "in the inventory" if host_configuration == HostConfiguration.SINGLE else \ f"in group {group_name}" message = f"Host {address}:{port} already exists {host_location_message}. Record was not edited." host_edited = False @@ -191,12 +202,9 @@ def add_group_to_inventory(self, group_name: str, group_port: str, group_object= existing_inventory_record = list(self._mongo_inventory.find({'address': group_name, "delete": False})) deleted_inventory_record = list(self._mongo_inventory.find({'address': group_name, "delete": True})) group = list(self._mongo_groups.find({group_name: {"$exists": 1}})) - if len(group) == 0 and len(existing_inventory_record) == 0: - group_added = True - message = f"Group {group_name} doesn't exist in the configuration. Treating {group_name} as a hostname." - elif len(group) == 0 and len(existing_inventory_record) > 0: + if len(group) == 0: group_added = False - message = f"{group_name} has already been configured. Record was not added." + message = f"Group {group_name} doesn't exist in the configuration. Record was not added." elif len(existing_inventory_record) > 0: group_added = False message = f"Group {group_name} has already been added to the inventory. Record was not added." @@ -229,8 +237,11 @@ def edit_group_in_inventory(self, group_name: str, group_id: str, group_object=N group_id = ObjectId(group_id) existing_inventory_record = list(self._mongo_inventory.find({'address': group_name, "delete": False})) deleted_inventory_record = list(self._mongo_inventory.find({'address': group_name, "delete": True})) - - if len(existing_inventory_record) == 0 or (len(existing_inventory_record) > 0 and existing_inventory_record[0]["_id"] == group_id): + group = list(self._mongo_groups.find({group_name: {"$exists": 1}})) + if len(group) == 0: + group_edited = False + message = f"Group {group_name} doesn't exist in the configuration. Record was not edited." + elif len(existing_inventory_record) == 0 or (len(existing_inventory_record) > 0 and existing_inventory_record[0]["_id"] == group_id): message = "success" group_edited = True if edit and group_object is not None: @@ -249,7 +260,7 @@ def edit_group_in_inventory(self, group_name: str, group_id: str, group_object=N if len(deleted_inventory_record) > 0: self._mongo_inventory.delete_one({"_id": deleted_inventory_record[0]["_id"]}) else: - message = f"Group wit name {group_name} already exists. Record was not edited." + message = f"Group with name {group_name} already exists. Record was not edited." group_edited = False return group_edited, message diff --git a/backend/SC4SNMP_UI_backend/groups/routes.py b/backend/SC4SNMP_UI_backend/groups/routes.py index 5c95049..cf27d5d 100644 --- a/backend/SC4SNMP_UI_backend/groups/routes.py +++ b/backend/SC4SNMP_UI_backend/groups/routes.py @@ -5,7 +5,7 @@ from SC4SNMP_UI_backend.common.backend_ui_conversions import GroupConversion, GroupDeviceConversion, InventoryConversion, \ get_group_or_profile_name_from_backend from copy import copy -from SC4SNMP_UI_backend.common.inventory_utils import HandleNewDevice +from SC4SNMP_UI_backend.common.inventory_utils import HandleNewDevice, get_inventory_type groups_blueprint = Blueprint('groups_blueprint', __name__) @@ -35,6 +35,10 @@ def add_group_record(): if len(same_name_groups) > 0: result = jsonify( {"message": f"Group with name {group_obj['groupName']} already exists. Group was not added."}), 400 + elif list(mongo_inventory.find({"address": group_obj['groupName'], "delete": False})): + result = jsonify( + {"message": f"In the inventory there is a record with name {group_obj['groupName']}. Group was not added."} + ), 400 else: group_obj = group_conversion.ui2backend(group_obj) mongo_groups.insert_one(group_obj) @@ -50,6 +54,10 @@ def update_group(group_id): if len(same_name_groups) > 0: result = jsonify( {"message": f"Group with name {group_obj['groupName']} already exists. Group was not edited."}), 400 + elif list(mongo_inventory.find({"address": group_obj['groupName'], "delete": False})): + result = jsonify( + {"message": f"In the inventory there is a record with name {group_obj['groupName']}. Group was not edited."} + ), 400 else: old_group = list(mongo_groups.find({'_id': ObjectId(group_id)}))[0] old_group_name = get_group_or_profile_name_from_backend(old_group) @@ -110,7 +118,8 @@ def get_devices_of_group(group_id, page_num, dev_per_page): def get_group_config_from_inventory(group_name): group_from_inventory = list(mongo_inventory.find({"address": group_name, "delete": False})) if len(group_from_inventory) > 0: - result = jsonify(inventory_conversion.backend2ui(group_from_inventory[0])), 200 + inventory_type = get_inventory_type(group_from_inventory[0]) + result = jsonify(inventory_conversion.backend2ui(group_from_inventory[0], inventory_type=inventory_type)), 200 else: result = "", 204 return result diff --git a/backend/SC4SNMP_UI_backend/inventory/routes.py b/backend/SC4SNMP_UI_backend/inventory/routes.py index 959e021..6966019 100644 --- a/backend/SC4SNMP_UI_backend/inventory/routes.py +++ b/backend/SC4SNMP_UI_backend/inventory/routes.py @@ -3,7 +3,7 @@ from flask_cors import cross_origin from SC4SNMP_UI_backend import mongo_client from SC4SNMP_UI_backend.common.backend_ui_conversions import InventoryConversion -from SC4SNMP_UI_backend.common.inventory_utils import HandleNewDevice +from SC4SNMP_UI_backend.common.inventory_utils import HandleNewDevice, get_inventory_type inventory_blueprint = Blueprint('inventory_blueprint', __name__) @@ -11,7 +11,6 @@ mongo_groups = mongo_client.sc4snmp.groups_ui mongo_inventory = mongo_client.sc4snmp.inventory_ui - @inventory_blueprint.route('/inventory//') @cross_origin() def get_inventory_list(page_num, dev_per_page): @@ -22,7 +21,8 @@ def get_inventory_list(page_num, dev_per_page): inventory = list(mongo_inventory.find({"delete": False}).skip(skips).limit(dev_per_page)) inventory_list = [] for inv in inventory: - inventory_list.append(inventory_conversion.backend2ui(inv)) + inventory_type = get_inventory_type(inv) + inventory_list.append(inventory_conversion.backend2ui(inv, inventory_type=inventory_type)) return jsonify(inventory_list) @@ -37,9 +37,10 @@ def get_inventory_count(): @cross_origin() def add_inventory_record(): inventory_obj = request.json + inventory_type = inventory_obj["inventoryType"] inventory_obj = inventory_conversion.ui2backend(inventory_obj, delete=False) handler = HandleNewDevice(mongo_groups, mongo_inventory) - if inventory_obj["address"][0].isdigit(): + if inventory_type == "Host": record_added, message = handler.add_single_host(inventory_obj["address"], str(inventory_obj["port"]), inventory_obj, True) else: @@ -68,23 +69,22 @@ def delete_inventory_record(inventory_id): @cross_origin() def update_inventory_record(inventory_id): inventory_obj = request.json + inventory_type = inventory_obj["inventoryType"] inventory_obj = inventory_conversion.ui2backend(inventory_obj, delete=False) current_inventory = list(mongo_inventory.find({"_id": ObjectId(inventory_id)}))[0] + current_inventory_type = get_inventory_type(current_inventory) handler = HandleNewDevice(mongo_groups, mongo_inventory) - is_current_a_single_host = current_inventory["address"][0].isdigit() - is_new_a_single_host = inventory_obj["address"][0].isdigit() - if is_current_a_single_host != is_new_a_single_host: + if inventory_type != current_inventory_type: result = jsonify({"message": "Can't edit single host to the group or group to the single host"}), 400 else: - if is_new_a_single_host: + if inventory_type == "Host": record_edited, message = handler.edit_single_host(inventory_obj["address"], str(inventory_obj["port"]), str(inventory_id), inventory_obj, True) else: record_edited, message = handler.edit_group_in_inventory(inventory_obj["address"], str(inventory_id), inventory_obj, True) if record_edited: if message == "success" or message is None: - print(message) result = jsonify("success"), 200 else: result = jsonify({"message": message}), 200 diff --git a/backend/tests/common/test_backend_ui_conversions.py b/backend/tests/common/test_backend_ui_conversions.py index 33d790d..0a41f41 100644 --- a/backend/tests/common/test_backend_ui_conversions.py +++ b/backend/tests/common/test_backend_ui_conversions.py @@ -207,6 +207,7 @@ def setUpClass(cls): cls.ui_inventory_1 = { "_id": common_id, + "inventoryType": "Host", "address": "11.0.78.114", "port": "161", "version": "3", @@ -234,6 +235,7 @@ def setUpClass(cls): cls.ui_inventory_2 = { "_id": common_id, + "inventoryType": "Group", "address": "group_1", "port": "1161", "version": "2c", @@ -320,8 +322,8 @@ def test_group_device_ui_to_backend(self): self.assertDictEqual(group_device_conversion.ui2backend(self.ui_group_device_4), device) def test_inventory_backend_to_ui(self): - self.assertDictEqual(inventory_conversion.backend2ui(self.backend_inventory_1), self.ui_inventory_1) - self.assertDictEqual(inventory_conversion.backend2ui(self.backend_inventory_2), self.ui_inventory_2) + self.assertDictEqual(inventory_conversion.backend2ui(self.backend_inventory_1, inventory_type="Host"), self.ui_inventory_1) + self.assertDictEqual(inventory_conversion.backend2ui(self.backend_inventory_2, inventory_type="Group"), self.ui_inventory_2) def test_inventory_ui_to_backend(self): back_inv = self.backend_inventory_1 diff --git a/backend/tests/ui_handling/get_endpoints/test_get_endpoints.py b/backend/tests/ui_handling/get_endpoints/test_get_endpoints.py index cc7b53b..b91591f 100644 --- a/backend/tests/ui_handling/get_endpoints/test_get_endpoints.py +++ b/backend/tests/ui_handling/get_endpoints/test_get_endpoints.py @@ -1,7 +1,6 @@ from unittest import mock from bson import ObjectId - @mock.patch("pymongo.collection.Collection.find") def test_get_profile_names(m_client, client): m_client.return_value = [{ @@ -264,8 +263,9 @@ def test_get_devices_of_group(m_client, client): assert response.json == third_result +@mock.patch("SC4SNMP_UI_backend.inventory.routes.get_inventory_type") @mock.patch("pymongo.cursor.Cursor.limit") -def test_get_inventory_list(m_cursor, client): +def test_get_inventory_list(m_cursor, m_get_inventory_type, client): common_id = "635916b2c8cb7a15f28af40a" m_cursor.side_effect = [ @@ -314,9 +314,12 @@ def test_get_inventory_list(m_cursor, client): ] ] + m_get_inventory_type.side_effect = ["Host", "Group", "Group"] + first_result = [ { "_id": common_id, + "inventoryType": "Host", "address": "11.0.78.114", "port": "161", "version": "3", @@ -329,6 +332,7 @@ def test_get_inventory_list(m_cursor, client): }, { "_id": common_id, + "inventoryType": "Group", "address": "group_1", "port": "1161", "version": "2c", @@ -344,6 +348,7 @@ def test_get_inventory_list(m_cursor, client): second_result = [ { "_id": common_id, + "inventoryType": "Group", "address": "group_2", "port": "161", "version": "3", diff --git a/backend/tests/ui_handling/post_endpoints/test_post_groups.py b/backend/tests/ui_handling/post_endpoints/test_post_groups.py index 85d2d69..be59eda 100644 --- a/backend/tests/ui_handling/post_endpoints/test_post_groups.py +++ b/backend/tests/ui_handling/post_endpoints/test_post_groups.py @@ -16,16 +16,21 @@ def test_add_group_record_success(m_find, m_insert, client): "group_1": [] } + find_calls = [ + call({'address': 'group_1', 'delete': False}), + call({f"group_1": {"$exists": True}}), + ] + m_find.side_effect = [[],[]] + response = client.post(f"/groups/add", json=ui_group) - m_find.return_value = [] m_insert.return_value = None - assert m_find.call_args == call({f"group_1": {"$exists": True}}) + m_find.has_calls(find_calls) assert m_insert.call_args == call(backend_group) assert response.json == "success" @mock.patch("pymongo.collection.Collection.insert_one") @mock.patch("pymongo.collection.Collection.find") -def test_add_group_record_success(m_find, m_insert, client): +def test_add_group_record_with_already_existing_name_failure(m_find, m_insert, client): ui_group = { "groupName": "group_1" } @@ -42,6 +47,22 @@ def test_add_group_record_success(m_find, m_insert, client): assert not m_insert.called assert response.json == {"message": "Group with name group_1 already exists. Group was not added."} +@mock.patch("pymongo.collection.Collection.insert_one") +@mock.patch("pymongo.collection.Collection.find") +def test_add_group_record_with_name_existing_in_inventory_as_hostname_failure(m_find, m_insert, client): + ui_group = { + "groupName": "test" + } + + m_find.side_effect = [ + [], + [{"address": "test"}] + ] + + response = client.post(f"/groups/add", json=ui_group) + assert not m_insert.called + assert response.json == {"message": "In the inventory there is a record with name test. Group was not added."} + # TEST UPDATING GROUP @mock.patch("pymongo.collection.Collection.update_one") @mock.patch("pymongo.collection.Collection.find") @@ -65,6 +86,7 @@ def test_update_group_success(m_find, m_update, client): ] m_find.side_effect = [ + [], [], [backend_group_old] ] @@ -105,6 +127,23 @@ def test_update_group_failure(m_find, m_update, client): assert not m_update.called assert response.json == {"message": "Group with name group_1_edit already exists. Group was not edited."} +@mock.patch("pymongo.collection.Collection.insert_one") +@mock.patch("pymongo.collection.Collection.find") +def test_update_group_record_with_name_existing_in_inventory_as_hostname_failure(m_find, m_insert, client): + ui_group = { + "_id": common_id, + "groupName": "test" + } + + m_find.side_effect = [ + [], + [{"address": "test"}] + ] + + response = client.post(f"/groups/update/{common_id}", json=ui_group) + assert not m_insert.called + assert response.json == {"message": "In the inventory there is a record with name test. Group was not edited."} + # TEST DELETING GROUP @mock.patch("pymongo.collection.Collection.find") @mock.patch("pymongo.collection.Collection.delete_one") @@ -224,7 +263,8 @@ def test_add_device_to_group_configured_in_inventory_success(m_find, m_update, c [], # call from HandleNewDevice._is_host_configured [], # call from HandleNewDevice._is_host_configured [group_inventory()], # call from HandleNewDevice._is_host_in_group - [backend_group_add_device_old()] # call from HandleNewDevice._is_host_in_group + [backend_group_add_device_old()], # call from HandleNewDevice._is_host_in_group + [] # call from HandleNewDevice.add_single_host ] calls_find = [ call({'_id': ObjectId(common_id)}, {"_id": 0}), # call from group/routes.add_device_to_group @@ -233,7 +273,8 @@ def test_add_device_to_group_configured_in_inventory_success(m_find, m_update, c call({'address': "2.2.2.2", 'port': 1161, "delete": False}), # call from HandleNewDevice._is_host_configured call({'address': "2.2.2.2", 'port': 1161, "delete": True}), # call from HandleNewDevice._is_host_configured call({"address": {"$regex": "^[a-zA-Z].*"}, "delete": False}), # call from HandleNewDevice._is_host_in_group - call({"group_1": {"$exists": 1}}) # call from HandleNewDevice._is_host_in_group + call({"group_1": {"$exists": 1}}), # call from HandleNewDevice._is_host_in_group + call({"2.2.2.2": {"$exists": True}}) # call from HandleNewDevice.add_single_host ] m_update.return_value = None @@ -308,6 +349,7 @@ def test_add_device_to_group_configured_in_inventory_failed(m_find, m_update, cl [backend_group_add_device_old()], # call from HandleNewDevice.add_group_host [existing_device_inventory], # call from HandleNewDevice._is_host_configured [], # call from HandleNewDevice._is_host_configured + [], # call from HandleNewDevice.add_single_host ] calls_find = [ call({'_id': ObjectId(common_id)}, {"_id": 0}), # call from group/routes.add_device_to_groupp @@ -315,12 +357,13 @@ def test_add_device_to_group_configured_in_inventory_failed(m_find, m_update, cl call({'_id': ObjectId(common_id)}, {"_id": 0}), # call from HandleNewDevice.add_group_host call({'address': "5.5.5.5", 'port': 161, "delete": False}), # call from HandleNewDevice._is_host_configured call({'address': "5.5.5.5", 'port': 161, "delete": True}), # call from HandleNewDevice._is_host_configured + call({"5.5.5.5": {"$exists": True}}), # call from HandleNewDevice.add_single_host ] response = client.post(f"/devices/add", json=ui_group_device_new) m_find.assert_has_calls(calls_find) assert not m_update.called - assert response.json == {'message': 'Host 5.5.5.5:161 already exists as a single host in the inventory. Record was not added.'} + assert response.json == {'message': 'Host 5.5.5.5:161 already exists in the inventory. Record was not added.'} # TEST UPDATING DEVICES diff --git a/backend/tests/ui_handling/post_endpoints/test_post_inventory.py b/backend/tests/ui_handling/post_endpoints/test_post_inventory.py index 7c164e2..ea28e2b 100644 --- a/backend/tests/ui_handling/post_endpoints/test_post_inventory.py +++ b/backend/tests/ui_handling/post_endpoints/test_post_inventory.py @@ -7,29 +7,56 @@ # TEST ADDING A SINGLE HOST ui_inventory_new = lambda : { - "address": "11.0.78.114", - "port": "161", - "version": "3", - "community": "", - "secret": "my_secret", - "walkInterval": 1800, - "securityEngine": "1234aabbccd", - "profiles": ["prof1", "prof2", "prof3"], - "smartProfiles": False - } + "inventoryType": "Host", + "address": "11.0.78.114", + "port": "161", + "version": "3", + "community": "", + "secret": "my_secret", + "walkInterval": 1800, + "securityEngine": "1234aabbccd", + "profiles": ["prof1", "prof2", "prof3"], + "smartProfiles": False +} backend_inventory_new = lambda : { - "address": "11.0.78.114", - "port": 161, - "version": "3", - "community": "", - "secret": "my_secret", - "walk_interval": 1800, - "security_engine": "1234aabbccd", - "profiles": "prof1;prof2;prof3", - "smart_profiles": False, - "delete": False - } + "address": "11.0.78.114", + "port": 161, + "version": "3", + "community": "", + "secret": "my_secret", + "walk_interval": 1800, + "security_engine": "1234aabbccd", + "profiles": "prof1;prof2;prof3", + "smart_profiles": False, + "delete": False +} + +ui_inventory_new_host_name = lambda : { + "inventoryType": "Host", + "address": "test", + "port": "161", + "version": "3", + "community": "", + "secret": "my_secret", + "walkInterval": 1800, + "securityEngine": "1234aabbccd", + "profiles": ["prof1", "prof2", "prof3"], + "smartProfiles": False +} + +backend_inventory_new_host_name = lambda : { + "address": "test", + "port": 161, + "version": "3", + "community": "", + "secret": "my_secret", + "walk_interval": 1800, + "security_engine": "1234aabbccd", + "profiles": "prof1;prof2;prof3", + "smart_profiles": False, + "delete": False +} @mock.patch("pymongo.collection.Collection.delete_one") @mock.patch("pymongo.collection.Collection.insert_one") @@ -44,12 +71,14 @@ def test_add_single_host_success(m_find, m_insert, m_delete, client): m_find.side_effect = [ [], # call from HandleNewDevice._is_host_configured [], # call from HandleNewDevice._is_host_configured - [] # call from HandleNewDevice._is_host_in_group + [], # call from HandleNewDevice._is_host_in_group + [], # call from HandleNewDevice.add_single_host ] calls_find = [ call({'address': "11.0.78.114", 'port': 161, "delete": False}), # call from HandleNewDevice._is_host_configured call({'address': "11.0.78.114", 'port': 161, "delete": True}), # call from HandleNewDevice._is_host_configured - call({"address": {"$regex": "^[a-zA-Z].*"}, "delete": False}) # call from HandleNewDevice._is_host_in_group + call({"address": {"$regex": "^[a-zA-Z].*"}, "delete": False}), # call from HandleNewDevice._is_host_in_group + call({"11.0.78.114": {"$exists": True}}), # call from HandleNewDevice.add_single_host ] @@ -76,7 +105,8 @@ def test_add_single_host_success(m_find, m_insert, m_delete, client): "smart_profiles": False, "delete": True }], # call from HandleNewDevice._is_host_configured - [] # call from HandleNewDevice._is_host_in_group + [], # call from HandleNewDevice._is_host_in_group + [], # call from HandleNewDevice.add_single_host ] @@ -86,6 +116,61 @@ def test_add_single_host_success(m_find, m_insert, m_delete, client): assert m_delete.call_args == call({"_id": ObjectId(common_id)}) assert response.json == "success" +@mock.patch("pymongo.collection.Collection.delete_one") +@mock.patch("pymongo.collection.Collection.insert_one") +@mock.patch("pymongo.collection.Collection.find") +def test_add_single_host_name_success(m_find, m_insert, m_delete, client): + # Test adding a new device, when there was no device with the same + # address and port with deleted flag set to True. + m_insert.return_value = None + m_delete.return_value = None + + m_find.side_effect = [ + [], # call from HandleNewDevice._is_host_configured + [], # call from HandleNewDevice._is_host_configured + [], # call from HandleNewDevice._is_host_in_group + [], # call from HandleNewDevice.add_single_host + ] + calls_find = [ + call({'address': "test", 'port': 161, "delete": False}), # call from HandleNewDevice._is_host_configured + call({'address': "test", 'port': 161, "delete": True}), # call from HandleNewDevice._is_host_configured + call({"address": {"$regex": "^[a-zA-Z].*"}, "delete": False}), # call from HandleNewDevice._is_host_in_group + call({"test": {"$exists": True}}), # call from HandleNewDevice.add_single_host + ] + + response = client.post(f"/inventory/add", json=ui_inventory_new_host_name()) + m_find.assert_has_calls(calls_find) + assert m_insert.call_args == call(backend_inventory_new_host_name()) + assert not m_delete.called + assert response.json == "success" + + # Test adding a new device when there was a device with the same + # address and port with deleted flag set to True. + m_find.side_effect = [ + [], # call from HandleNewDevice._is_host_configured + [{ + "_id": ObjectId(common_id), + "address": "test", + "port": 161, + "version": "3", + "community": "", + "secret": "my_secret", + "walk_interval": 1800, + "security_engine": "1234aabbccd", + "profiles": "prof1;prof2;prof3", + "smart_profiles": False, + "delete": True + }], # call from HandleNewDevice._is_host_configured + [], # call from HandleNewDevice._is_host_in_group + [], # call from HandleNewDevice.add_single_host + ] + + response = client.post(f"/inventory/add", json=ui_inventory_new_host_name()) + m_find.assert_has_calls(calls_find) + assert m_insert.call_args == call(backend_inventory_new_host_name()) + assert m_delete.call_args == call({"_id": ObjectId(common_id)}) + assert response.json == "success" + @mock.patch("pymongo.collection.Collection.delete_one") @mock.patch("pymongo.collection.Collection.insert_one") @mock.patch("pymongo.collection.Collection.find") @@ -109,19 +194,32 @@ def test_add_single_host_failure(m_find, m_insert, m_delete, client): "delete": False }], # call from HandleNewDevice._is_host_configured [], # call from HandleNewDevice._is_host_configured + [], # call from HandleNewDevice.add_single_host ] calls_find = [ call({'address': "11.0.78.114", 'port': 161, "delete": False}), # call from HandleNewDevice._is_host_configured call({'address': "11.0.78.114", 'port': 161, "delete": True}), # call from HandleNewDevice._is_host_configured + call({'11.0.78.114': {"$exists": True}}), # call from HandleNewDevice.add_single_host ] response = client.post(f"/inventory/add", json=ui_inventory_new()) m_find.assert_has_calls(calls_find) assert not m_delete.called assert not m_insert.called - assert response.json == {"message": "Host 11.0.78.114:161 already exists as a single host in the inventory. " + assert response.json == {"message": "Host 11.0.78.114:161 already exists in the inventory. " "Record was not added."} + m_find.side_effect = [ + [], # call from HandleNewDevice._is_host_configured + [], # call from HandleNewDevice._is_host_configured + [], # call from HandleNewDevice._is_host_in_group + [{"test":[]}], # call from HandleNewDevice.add_single_host + ] + response = client.post(f"/inventory/add", json=ui_inventory_new_host_name()) + assert not m_delete.called + assert not m_insert.called + assert response.json == {"message": "There is a group with the same name configured. Record test can't be added as a single host."} + # TEST UPDATING A SINGLE HOST backend_inventory_old = lambda : { @@ -137,15 +235,18 @@ def test_add_single_host_failure(m_find, m_insert, m_delete, client): "smart_profiles": False, "delete": False } + +@mock.patch("SC4SNMP_UI_backend.inventory.routes.get_inventory_type") @mock.patch("pymongo.collection.Collection.delete_one") @mock.patch("pymongo.collection.Collection.update_one") @mock.patch("pymongo.collection.Collection.insert_one") @mock.patch("pymongo.collection.Collection.find") -def test_edit_single_host_success(m_find, m_insert, m_update, m_delete, client): +def test_edit_single_host_success(m_find, m_insert, m_update, m_delete, m_get_inventory_type, client): # Test editing a device without changing its address and port m_insert.return_value = None m_update.return_value = None m_delete.return_value = None + m_get_inventory_type.return_value = "Host" m_find.side_effect = [ [backend_inventory_old()], # call from inventory/routes.update_inventory_record [backend_inventory_old()], # call from HandleNewDevice._is_host_configured @@ -168,16 +269,19 @@ def test_edit_single_host_success(m_find, m_insert, m_update, m_delete, client): assert response.json == "success" +@mock.patch("SC4SNMP_UI_backend.inventory.routes.get_inventory_type") @mock.patch("pymongo.collection.Collection.delete_one") @mock.patch("pymongo.collection.Collection.update_one") @mock.patch("pymongo.collection.Collection.insert_one") @mock.patch("pymongo.collection.Collection.find") -def test_edit_single_host_address_and_port_success(m_find, m_insert, m_update, m_delete, client): +def test_edit_single_host_address_and_port_success(m_find, m_insert, m_update, m_delete, m_get_inventory_type, client): # Test editing a device with changing its address and port m_insert.return_value = None m_update.return_value = None m_delete.return_value = None + m_get_inventory_type.return_value = "Host" ui_inventory_new_address_port = { + "inventoryType": "Host", "address": "1.0.0.0", "port": "1111", "version": "3", @@ -223,6 +327,7 @@ def test_edit_single_host_address_and_port_success(m_find, m_insert, m_update, m [], # call from HandleNewDevice._is_host_configured [deleted_host_backend], # call from HandleNewDevice._is_host_configured [], # call from HandleNewDevice._is_host_in_group + [], # call from HandleNewDevice.add_single_host ] calls_find = [ @@ -234,6 +339,88 @@ def test_edit_single_host_address_and_port_success(m_find, m_insert, m_update, m call({'address': "1.0.0.0", 'port': 1111, "delete": False}), # call from HandleNewDevice._is_host_configured call({'address': "1.0.0.0", 'port': 1111, "delete": True}), # call from HandleNewDevice._is_host_configured call({"address": {"$regex": "^[a-zA-Z].*"}, "delete": False}), # call from HandleNewDevice._is_host_in_group + call({'1.0.0.0': {"$exists": True}}), # call from HandleNewDevice.add_single_host + ] + + response = client.post(f"/inventory/update/{common_id}", json=ui_inventory_new_address_port) + m_find.assert_has_calls(calls_find) + assert m_insert.call_args == call(backend_inventory_new_address_port) + assert m_delete.call_args == call({"_id": ObjectId("43EE0BCBA668527E7106E4F5")}) + assert m_update.call_args == call({"_id": ObjectId(common_id)}, {"$set": {"delete": True}}) + assert response.json == { + "message": "Address or port was edited which resulted in deleting the old device and creating " \ + "the new one at the end of the list."} + +@mock.patch("SC4SNMP_UI_backend.inventory.routes.get_inventory_type") +@mock.patch("pymongo.collection.Collection.delete_one") +@mock.patch("pymongo.collection.Collection.update_one") +@mock.patch("pymongo.collection.Collection.insert_one") +@mock.patch("pymongo.collection.Collection.find") +def test_edit_ip_to_hostname_success(m_find, m_insert, m_update, m_delete, m_get_inventory_type, client): + m_insert.return_value = None + m_update.return_value = None + m_delete.return_value = None + m_get_inventory_type.return_value = "Host" + ui_inventory_new_address_port = { + "inventoryType": "Host", + "address": "test", + "port": "1111", + "version": "3", + "community": "", + "secret": "my_secret_new", + "walkInterval": 1800, + "securityEngine": "1234aabbccd", + "profiles": ["prof1", "prof2", "prof3"], + "smartProfiles": False + } + backend_inventory_new_address_port = { + "address": "test", + "port": 1111, + "version": "3", + "community": "", + "secret": "my_secret_new", + "walk_interval": 1800, + "security_engine": "1234aabbccd", + "profiles": "prof1;prof2;prof3", + "smart_profiles": False, + "delete": False + } + deleted_host_backend = { + "_id": ObjectId("43EE0BCBA668527E7106E4F5"), + "address": "11.0.78.114", + "port": 161, + "version": "3", + "community": "", + "secret": "my_secret", + "walk_interval": 1800, + "security_engine": "1234aabbccd", + "profiles": "prof1;prof2;prof3", + "smart_profiles": False, + "delete": True + } + + m_find.side_effect = [ + [backend_inventory_old()], # call from inventory/routes.update_inventory_record + [], # call from HandleNewDevice._is_host_configured + [deleted_host_backend], # call from HandleNewDevice._is_host_configured + [], # call from HandleNewDevice._is_host_in_group + [backend_inventory_old()], # call from HandleNewDevice.edit_single_host + [], # call from HandleNewDevice._is_host_configured + [deleted_host_backend], # call from HandleNewDevice._is_host_configured + [], # call from HandleNewDevice._is_host_in_group + [], # call from HandleNewDevice.add_single_host + ] + + calls_find = [ + call({"_id": ObjectId(common_id)}), # call from inventory/routes.update_inventory_record + call({'address': "test", 'port': 1111, "delete": False}), # call from HandleNewDevice._is_host_configured + call({'address': "test", 'port': 1111, "delete": True}), # call from HandleNewDevice._is_host_configured + call({"address": {"$regex": "^[a-zA-Z].*"}, "delete": False}), # call from HandleNewDevice._is_host_in_group + call({"_id": ObjectId(common_id)}), + call({'address': "test", 'port': 1111, "delete": False}), # call from HandleNewDevice._is_host_configured + call({'address': "test", 'port': 1111, "delete": True}), # call from HandleNewDevice._is_host_configured + call({"address": {"$regex": "^[a-zA-Z].*"}, "delete": False}), # call from HandleNewDevice._is_host_in_group + call({'test': {"$exists": True}}), # call from HandleNewDevice.add_single_host ] response = client.post(f"/inventory/update/{common_id}", json=ui_inventory_new_address_port) @@ -259,14 +446,17 @@ def test_edit_single_host_address_and_port_success(m_find, m_insert, m_update, m "smart_profiles": False, "delete": False } + +@mock.patch("SC4SNMP_UI_backend.inventory.routes.get_inventory_type") @mock.patch("pymongo.collection.Collection.delete_one") @mock.patch("pymongo.collection.Collection.update_one") @mock.patch("pymongo.collection.Collection.insert_one") @mock.patch("pymongo.collection.Collection.find") -def test_edit_single_host_failed(m_find, m_insert, m_update, m_delete, client): +def test_edit_single_host_failed(m_find, m_insert, m_update, m_delete, m_get_inventory_type, client): existing_id = "035916b2c8cb7a15f28af40b" ui_inventory_new = { + "inventoryType": "Host", "address": "0.0.0.0", "port": "1161", "version": "3", @@ -281,6 +471,7 @@ def test_edit_single_host_failed(m_find, m_insert, m_update, m_delete, client): m_insert.return_value = None m_update.return_value = None m_delete.return_value = None + m_get_inventory_type.return_value = "Host" m_find.side_effect = [ [backend_inventory_old()], # call from inventory/routes.update_inventory_record @@ -304,21 +495,55 @@ def test_edit_single_host_failed(m_find, m_insert, m_update, m_delete, client): call({"_id": ObjectId(common_id)}), # call from inventory/routes.update_inventory_record call({'address': "0.0.0.0", 'port': 1161, "delete": False}), # call from HandleNewDevice._is_host_configured call({'address': "0.0.0.0", 'port': 1161, "delete": True}), # call from HandleNewDevice._is_host_configured - ] response = client.post(f"/inventory/update/{common_id}", json=ui_inventory_new) m_find.assert_has_calls(calls_find) - assert response.json == {"message": "Host 0.0.0.0:1161 already exists as a single host in the inventory. " + assert response.json == {"message": "Host 0.0.0.0:1161 already exists in the inventory. " "Record was not edited."} assert response.status_code == 400 assert not m_insert.called assert not m_update.called assert not m_delete.called + ui_inventory_new = { + "inventoryType": "Host", + "address": "test", + "port": "1161", + "version": "3", + "community": "", + "secret": "my_secret", + "walkInterval": 1800, + "securityEngine": "1234aabbccd", + "profiles": ["prof1", "prof2", "prof3"], + "smartProfiles": False + } + + m_find.side_effect = [ + [backend_inventory_old()], # call from inventory/routes.update_inventory_record + [], # call from HandleNewDevice._is_host_configured + [], # call from HandleNewDevice._is_host_configured + [], # call from HandleNewDevice._is_host_in_group + [backend_inventory_old()], # call from HandleNewDevice.edit_single_host + [], # call from HandleNewDevice._is_host_configured + [], # call from HandleNewDevice._is_host_configured + [], # call from HandleNewDevice._is_host_in_group + [{"test":[]}], # call from HandleNewDevice.add_single_host + ] + response = client.post(f"/inventory/update/{common_id}", json=ui_inventory_new) + assert response.json == {"message": "There is a group with the same name configured. Record test can't be added as a single host."} + assert response.status_code == 400 + assert not m_insert.called + assert not m_update.called + assert not m_delete.called + + + + # TEST ADDING A GROUP new_group_ui_inventory = lambda : { + "inventoryType": "Group", "address": "group_1", "port": "161", "version": "3", @@ -383,7 +608,8 @@ def test_add_group_success(m_find, m_insert, m_delete, client): [], # call from HandleNewDevice._is_host_configured [], # call from HandleNewDevice._is_host_configured [existing_group_inventory_backend()], # call from HandleNewDevice._is_host_in_group - [existing_group_backend()] # call from HandleNewDevice._is_host_in_group + [existing_group_backend()], # call from HandleNewDevice._is_host_in_group + [], # call from HandleNewDevice.add_single_host ] calls_find = [ @@ -393,7 +619,8 @@ def test_add_group_success(m_find, m_insert, m_delete, client): call({'address': "1.2.3.4", 'port': 161, "delete": False}), # call from HandleNewDevice._is_host_configured call({'address': "1.2.3.4", 'port': 161, "delete": True}), # call from HandleNewDevice._is_host_configured call({"address": {"$regex": "^[a-zA-Z].*"}, "delete": False}), # call from HandleNewDevice._is_host_in_group - call({"group_2": {"$exists": 1}}) # call from HandleNewDevice._is_host_in_group + call({"group_2": {"$exists": 1}}), # call from HandleNewDevice._is_host_in_group + call({'1.2.3.4': {"$exists": True}}), # call from HandleNewDevice.add_single_host ] response = client.post(f"/inventory/add", json=new_group_ui_inventory()) @@ -422,7 +649,8 @@ def test_add_group_success(m_find, m_insert, m_delete, client): [], # call from HandleNewDevice._is_host_configured [], # call from HandleNewDevice._is_host_configured [existing_group_inventory_backend()], # call from HandleNewDevice._is_host_in_group - [existing_group_backend()] # call from HandleNewDevice._is_host_in_group + [existing_group_backend()], # call from HandleNewDevice._is_host_in_group + [], # call from HandleNewDevice.add_single_host ] response = client.post(f"/inventory/add", json=new_group_ui_inventory()) @@ -467,6 +695,7 @@ def test_add_group_with_hosts_configured_failure(m_find, m_insert, m_delete, cli m_delete.return_value = None new_group_ui_failure = { + "inventoryType": "Group", "address": "group_1", "port": "161", "version": "3", @@ -490,7 +719,8 @@ def test_add_group_with_hosts_configured_failure(m_find, m_insert, m_delete, cli [], # call from HandleNewDevice._is_host_configured [], # call from HandleNewDevice._is_host_configured [existing_group_inventory_backend()], # call from HandleNewDevice._is_host_in_group - [existing_group_backend()] # call from HandleNewDevice._is_host_in_group + [existing_group_backend()], # call from HandleNewDevice._is_host_in_group + [], # call from HandleNewDevice.add_single_host ] calls_find = [ @@ -500,7 +730,8 @@ def test_add_group_with_hosts_configured_failure(m_find, m_insert, m_delete, cli call({'address': "0.0.0.0", 'port': 161, "delete": False}), # call from HandleNewDevice._is_host_configured call({'address': "0.0.0.0", 'port': 161, "delete": True}), # call from HandleNewDevice._is_host_configured call({"address": {"$regex": "^[a-zA-Z].*"}, "delete": False}), # call from HandleNewDevice._is_host_in_group - call({"group_2": {"$exists": 1}}) # call from HandleNewDevice._is_host_in_group + call({"group_2": {"$exists": 1}}), # call from HandleNewDevice._is_host_in_group + call({'0.0.0.0': {"$exists": True}}), # call from HandleNewDevice.add_single_host ] response = client.post(f"/inventory/add", json=new_group_ui_failure) @@ -519,6 +750,7 @@ def test_add_group_with_host_configured_multiple_times_failure(m_find, m_insert, m_delete.return_value = None new_group_ui_failure = { + "inventoryType": "Group", "address": "group_1", "port": "161", "version": "3", @@ -548,12 +780,14 @@ def test_add_group_with_host_configured_multiple_times_failure(m_find, m_insert, [], # call from HandleNewDevice._is_host_configured [existing_group_inventory_backend()], # call from HandleNewDevice._is_host_in_group [existing_group_backend()], # call from HandleNewDevice._is_host_in_group + [], # call from HandleNewDevice.add_single_host # second iteration in HandleNewDevice.add_group_to_inventory [], # call from HandleNewDevice._is_host_configured [], # call from HandleNewDevice._is_host_configured [existing_group_inventory_backend()], # call from HandleNewDevice._is_host_in_group - [existing_group_backend()] # call from HandleNewDevice._is_host_in_group + [existing_group_backend()], # call from HandleNewDevice._is_host_in_group + [], # call from HandleNewDevice.add_single_host ] calls_find = [ @@ -566,12 +800,14 @@ def test_add_group_with_host_configured_multiple_times_failure(m_find, m_insert, call({'address': "1.1.1.1", 'port': 161, "delete": True}), # call from HandleNewDevice._is_host_configured call({"address": {"$regex": "^[a-zA-Z].*"}, "delete": False}), # call from HandleNewDevice._is_host_in_group call({"group_2": {"$exists": 1}}), # call from HandleNewDevice._is_host_in_group + call({'1.1.1.1': {"$exists": True}}), # call from HandleNewDevice.add_single_host # second iteration in HandleNewDevice.add_group_to_inventory call({'address': "1.1.1.1", 'port': 161, "delete": False}), # call from HandleNewDevice._is_host_configured call({'address': "1.1.1.1", 'port': 161, "delete": True}), # call from HandleNewDevice._is_host_configured call({"address": {"$regex": "^[a-zA-Z].*"}, "delete": False}), # call from HandleNewDevice._is_host_in_group - call({"group_2": {"$exists": 1}}) # call from HandleNewDevice._is_host_in_group + call({"group_2": {"$exists": 1}}), # call from HandleNewDevice._is_host_in_group + call({'1.1.1.1': {"$exists": True}}), # call from HandleNewDevice.add_single_host ] response = client.post(f"/inventory/add", json=new_group_ui_failure) @@ -604,10 +840,10 @@ def test_add_group_without_configuration(m_find, m_insert, m_delete, client): response = client.post(f"/inventory/add", json=new_group_ui_inventory()) m_find.assert_has_calls(calls_find) - assert m_insert.call_args == call(new_group_backend_inventory()) + assert not m_insert.called assert not m_delete.called assert response.json == {"message": "Group group_1 doesn't exist in the configuration. " - "Treating group_1 as a hostname."} + "Record was not added."} @mock.patch("pymongo.collection.Collection.delete_one") @@ -633,13 +869,14 @@ def test_add_group_without_configuration_failure(m_find, m_insert, m_delete, cli m_find.assert_has_calls(calls_find) assert not m_insert.called assert not m_delete.called - assert response.json == {"message": "group_1 has already been configured. Record was not added."} + assert response.json == {"message": "Group group_1 doesn't exist in the configuration. Record was not added."} # TEST UPDATING A GROUP -ui_edited_group = lambda : { +ui_edited_inventory_group = lambda : { + "inventoryType": "Group", "address": "group_1", "port": "161", "version": "3", @@ -651,7 +888,7 @@ def test_add_group_without_configuration_failure(m_find, m_insert, m_delete, cli "smartProfiles": False } -edited_group = lambda : { +edited_inventory_group = lambda : { "address": "group_1", "port": 161, "version": "3", @@ -664,7 +901,7 @@ def test_add_group_without_configuration_failure(m_find, m_insert, m_delete, cli "delete": False } -backend_existing_edit_group = lambda : { +backend_inventory_existing_edit_group = lambda : { "_id": ObjectId(common_id), "address": "group_1", "port": 161, @@ -678,6 +915,11 @@ def test_add_group_without_configuration_failure(m_find, m_insert, m_delete, cli "delete": False } +backend_existing_edit_group = lambda : { + "_id": ObjectId(common_id), + "group_1": [{"address": "1.1.1.1"}] +} + @mock.patch("pymongo.collection.Collection.delete_one") @mock.patch("pymongo.collection.Collection.update_one") @mock.patch("pymongo.collection.Collection.insert_one") @@ -689,22 +931,26 @@ def test_update_group_without_changing_name_success(m_find, m_insert, m_update, m_delete.return_value = None m_find.side_effect = [ - [backend_existing_edit_group()], # call from HandleNewDevice.update_inventory_record - [backend_existing_edit_group()], # call from HandleNewDevice.edit_group_in_inventory + [backend_inventory_existing_edit_group()], # call from inventory/routes/update_inventory_record + [backend_existing_edit_group()], # call from inventory/routes/get_inventory_type + [backend_inventory_existing_edit_group()], # call from HandleNewDevice.edit_group_in_inventory [], # call from HandleNewDevice.edit_group_in_inventory - [backend_existing_edit_group()] # call from HandleNewDevice.edit_group_in_inventory + [{"group_1": []}], # call from HandleNewDevice.edit_group_in_inventory + [backend_inventory_existing_edit_group()] # call from HandleNewDevice.edit_group_in_inventory ] calls_find = [ - call({"_id": ObjectId(common_id)}), # call from HandleNewDevice.update_inventory_record + call({"_id": ObjectId(common_id)}), # call from inventory/routes/update_inventory_record + call({"group_1": {"$exists": 1}}), # call from inventory/routes/get_inventory_type call({'address': "group_1", "delete": False}), # call from HandleNewDevice.edit_group_in_inventory call({'address': "group_1", "delete": True}), # call from HandleNewDevice.edit_group_in_inventory + call({"group_1": {"$exists": 1}}), # call from HandleNewDevice.edit_group_in_inventory call({"_id": ObjectId(common_id)}) # call from HandleNewDevice.edit_group_in_inventory ] - response = client.post(f"/inventory/update/{common_id}", json=ui_edited_group()) + response = client.post(f"/inventory/update/{common_id}", json=ui_edited_inventory_group()) m_find.assert_has_calls(calls_find) - assert m_update.call_args == call({"_id": ObjectId(common_id)}, {"$set": edited_group()}) + assert m_update.call_args == call({"_id": ObjectId(common_id)}, {"$set": edited_inventory_group()}) assert not m_insert.called assert not m_delete.called assert response.json == "success" @@ -721,6 +967,7 @@ def test_update_group_with_changing_name_success(m_find, m_insert, m_update, m_d m_delete.return_value = None new_name_group_ui = { + "inventoryType": "Group", "address": "group_2", "port": "161", "version": "3", @@ -751,19 +998,23 @@ def test_update_group_with_changing_name_success(m_find, m_insert, m_update, m_d } m_find.side_effect = [ - [backend_existing_edit_group()], # call from HandleNewDevice.update_inventory_record + [backend_inventory_existing_edit_group()], # call from inventory/routes/update_inventory_record + [backend_existing_edit_group()], # call from inventory/routes/get_inventory_type [], # call from HandleNewDevice.edit_group_in_inventory [], # call from HandleNewDevice.edit_group_in_inventory - [backend_existing_edit_group()], # call from HandleNewDevice.edit_group_in_inventory + [{"group_2": []}], # call from HandleNewDevice.edit_group_in_inventory + [backend_inventory_existing_edit_group()], # call from HandleNewDevice.edit_group_in_inventory [], # call from HandleNewDevice.add_group_to_inventory [], # call from HandleNewDevice.add_group_to_inventory [second_group_backend] # call from HandleNewDevice.add_group_to_inventory ] calls_find = [ - call({"_id": ObjectId(common_id)}), # call from HandleNewDevice.update_inventory_record + call({"_id": ObjectId(common_id)}), # call from inventory/routes/update_inventory_record + call({"group_1": {"$exists": 1}}), # call from inventory/routes/get_inventory_type call({'address': "group_2", "delete": False}), # call from HandleNewDevice.edit_group_in_inventory call({'address': "group_2", "delete": True}), # call from HandleNewDevice.edit_group_in_inventory + call({"group_2": {"$exists": 1}}), # call from HandleNewDevice.edit_group_in_inventory call({"_id": ObjectId(common_id)}), # call from HandleNewDevice.edit_group_in_inventory call({'address': "group_2", "delete": False}), # call from HandleNewDevice.add_group_to_inventory call({'address': "group_2", "delete": True}), # call from HandleNewDevice.add_group_to_inventory @@ -788,6 +1039,7 @@ def test_update_group_to_already_configured_failure(m_find, m_insert, m_update, m_delete.return_value = None new_name_group_ui = { + "inventoryType": "Group", "address": "group_2", "port": "161", "version": "3", @@ -814,15 +1066,19 @@ def test_update_group_to_already_configured_failure(m_find, m_insert, m_update, } m_find.side_effect = [ - [backend_existing_edit_group()], # call from HandleNewDevice.update_inventory_record + [backend_inventory_existing_edit_group()], # call from inventory/routes/update_inventory_record + [backend_existing_edit_group()], # call from inventory/routes/get_inventory_type [inventory_existing_other_group], # call from HandleNewDevice.edit_group_in_inventory - [] # call from HandleNewDevice.edit_group_in_inventory + [], # call from HandleNewDevice.edit_group_in_inventory + [{"group_2": []}], # call from HandleNewDevice.edit_group_in_inventory ] calls_find = [ - call({"_id": ObjectId(common_id)}), # call from HandleNewDevice.update_inventory_record + call({"_id": ObjectId(common_id)}), # call from inventory/routes/update_inventory_record + call({"group_1": {"$exists": 1}}), # call from inventory/routes/get_inventory_type call({'address': "group_2", "delete": False}), # call from HandleNewDevice.edit_group_in_inventory call({'address': "group_2", "delete": True}), # call from HandleNewDevice.edit_group_in_inventory + call({"group_2": {"$exists": 1}}), # call from HandleNewDevice.edit_group_in_inventory ] response = client.post(f"/inventory/update/{common_id}", json=new_name_group_ui) @@ -830,7 +1086,7 @@ def test_update_group_to_already_configured_failure(m_find, m_insert, m_update, assert not m_update.called assert not m_insert.called assert not m_delete.called - assert response.json == {"message": "Group wit name group_2 already exists. Record was not edited."} + assert response.json == {"message": "Group with name group_2 already exists. Record was not edited."} @mock.patch("pymongo.collection.Collection.delete_one") @mock.patch("pymongo.collection.Collection.update_one") @@ -842,6 +1098,7 @@ def test_update_group_to_other_group_with_host_already_configured_failure(m_find m_delete.return_value = None new_group_ui_failure = { + "inventoryType": "Group", "address": "group_3", "port": "161", "version": "3", @@ -859,10 +1116,12 @@ def test_update_group_to_other_group_with_host_already_configured_failure(m_find } m_find.side_effect = [ - [backend_existing_edit_group()], # call from HandleNewDevice.update_inventory_record + [backend_inventory_existing_edit_group()], # call from inventory/routes/update_inventory_record + [backend_existing_edit_group()], # call from inventory/routes/get_inventory_type [], # call from HandleNewDevice.edit_group_in_inventory [], # call from HandleNewDevice.edit_group_in_inventory - [backend_existing_edit_group()], # call from HandleNewDevice.edit_group_in_inventory + [{"group_3": []}], # call from HandleNewDevice.edit_group_in_inventory + [backend_inventory_existing_edit_group()], # call from HandleNewDevice.edit_group_in_inventory [], # call from HandleNewDevice.add_group_to_inventory [], # call from HandleNewDevice.add_group_to_inventory @@ -870,13 +1129,16 @@ def test_update_group_to_other_group_with_host_already_configured_failure(m_find [], # call from HandleNewDevice._is_host_configured [], # call from HandleNewDevice._is_host_configured [existing_group_inventory_backend()], # call from HandleNewDevice._is_host_in_group - [existing_group_backend()] # call from HandleNewDevice._is_host_in_group + [existing_group_backend()], # call from HandleNewDevice._is_host_in_group + [], # call from HandleNewDevice.add_single_host ] calls_find = [ - call({"_id": ObjectId(common_id)}), # call from HandleNewDevice.update_inventory_record + call({"_id": ObjectId(common_id)}), # call from inventory/routes/update_inventory_record + call({"group_1": {"$exists": 1}}), # call from inventory/routes/get_inventory_type call({'address': "group_3", "delete": False}), # call from HandleNewDevice.edit_group_in_inventory call({'address': "group_3", "delete": True}), # call from HandleNewDevice.edit_group_in_inventory + call({"group_3": {"$exists": 1}}), # call from HandleNewDevice.edit_group_in_inventory call({"_id": ObjectId(common_id)}), # call from HandleNewDevice.edit_group_in_inventory call({'address': "group_3", "delete": False}), # call from HandleNewDevice.add_group_to_inventory @@ -885,7 +1147,8 @@ def test_update_group_to_other_group_with_host_already_configured_failure(m_find call({'address': "0.0.0.0", 'port': 161, "delete": False}), # call from HandleNewDevice._is_host_configured call({'address': "0.0.0.0", 'port': 161, "delete": True}), # call from HandleNewDevice._is_host_configured call({"address": {"$regex": "^[a-zA-Z].*"}, "delete": False}), # call from HandleNewDevice._is_host_in_group - call({"group_2": {"$exists": 1}}) # call from HandleNewDevice._is_host_in_group + call({"group_2": {"$exists": 1}}), # call from HandleNewDevice._is_host_in_group + call({'0.0.0.0': {"$exists": True}}), # call from HandleNewDevice.add_single_host ] response = client.post(f"/inventory/update/{common_id}", json=new_group_ui_failure) @@ -896,16 +1159,19 @@ def test_update_group_to_other_group_with_host_already_configured_failure(m_find "Host 0.0.0.0:161 already exists in group group_2. Record was not added."} +@mock.patch("SC4SNMP_UI_backend.inventory.routes.get_inventory_type") @mock.patch("pymongo.collection.Collection.delete_one") @mock.patch("pymongo.collection.Collection.update_one") @mock.patch("pymongo.collection.Collection.insert_one") @mock.patch("pymongo.collection.Collection.find") -def test_update_group_host_or_host_to_group_failure(m_find, m_insert, m_update, m_delete, client): +def test_update_group_host_or_host_to_group_failure(m_find, m_insert, m_update, m_delete, m_get_inventory_type, client): m_insert.return_value = None m_update.return_value = None m_delete.return_value = None + m_get_inventory_type.return_value = "Group" ui_edit_group_to_host = { + "inventoryType": "Host", "address": "1.1.1.1", "port": "161", "version": "3", @@ -918,11 +1184,11 @@ def test_update_group_host_or_host_to_group_failure(m_find, m_insert, m_update, } m_find.side_effect = [ - [backend_existing_edit_group()], # call from HandleNewDevice.update_inventory_record + [backend_inventory_existing_edit_group()], # call from inventory/routes/update_inventory_record ] calls_find = [ - call({"_id": ObjectId(common_id)}), # call from HandleNewDevice.update_inventory_record + call({"_id": ObjectId(common_id)}), # call from inventory/routes/update_inventory_record ] response = client.post(f"/inventory/update/{common_id}", json=ui_edit_group_to_host) @@ -932,6 +1198,7 @@ def test_update_group_host_or_host_to_group_failure(m_find, m_insert, m_update, assert not m_delete.called assert response.json == {"message": "Can't edit single host to the group or group to the single host"} + m_get_inventory_type.return_value = "Host" backend_edit_host_to_group = { "_id": ObjectId(common_id), "address": "1.1.1.1", @@ -947,6 +1214,7 @@ def test_update_group_host_or_host_to_group_failure(m_find, m_insert, m_update, } ui_edit_group_to_host2 = { + "inventoryType": "Group", "address": "group_1", "port": "161", "version": "3", diff --git a/frontend/packages/manager/src/components/ErrorsModal.jsx b/frontend/packages/manager/src/components/ErrorsModal.jsx index 17b7055..e8af727 100644 --- a/frontend/packages/manager/src/components/ErrorsModal.jsx +++ b/frontend/packages/manager/src/components/ErrorsModal.jsx @@ -1,15 +1,16 @@ -import React, { useState, useRef, useContext } from 'react'; +import React, { useContext } from 'react'; import Button from '@splunk/react-ui/Button'; import Modal from '@splunk/react-ui/Modal'; import P from '@splunk/react-ui/Paragraph'; +import Message from "@splunk/react-ui/Message"; import ErrorsModalContext from "../store/errors-modal-contxt"; function ErrorsModal() { const ErrCtx = useContext(ErrorsModalContext); - const modalToggle = useRef(null); const handleRequestClose = () => { ErrCtx.setOpen(false); + ErrCtx.setErrorType("info"); ErrCtx.setMessage(""); }; @@ -17,7 +18,21 @@ function ErrorsModal() {
-

{ErrCtx.message}

+ { + ErrCtx.errorType === "info" ?

{ErrCtx.message}

: null + } + { + ErrCtx.errorType === "warning" ? + + {ErrCtx.message} + : null + } + { + ErrCtx.errorType === "error" ? + + {ErrCtx.message} + : null + }