diff --git a/roles/importer/files/importer/model_controllers/fwconfig_import_object.py b/roles/importer/files/importer/model_controllers/fwconfig_import_object.py index 8d850e90a0..55b69178a7 100644 --- a/roles/importer/files/importer/model_controllers/fwconfig_import_object.py +++ b/roles/importer/files/importer/model_controllers/fwconfig_import_object.py @@ -459,14 +459,14 @@ def get_config_objects(self, typ: Type, prev_config: FwConfigNormalized) -> tupl return prev_config.service_objects, self.normalized_config.service_objects return prev_config.users, self.normalized_config.users - def get_id(self, typ: Type, uid: str, before_update: bool = False) -> int | None: + def get_id(self, typ: Type, uid: str, before_update: bool = False) -> int: if typ == Type.NETWORK_OBJECT: return self.uid2id_mapper.get_network_object_id(uid, before_update) if typ == Type.SERVICE_OBJECT: return self.uid2id_mapper.get_service_object_id(uid, before_update) return self.uid2id_mapper.get_user_id(uid, before_update) - def get_local_id(self, typ: Type, uid: str, before_update: bool = False) -> int | None: + def get_local_id(self, typ: Type, uid: str, before_update: bool = False) -> int: if typ == Type.NETWORK_OBJECT: return self.uid2id_mapper.get_network_object_id(uid, before_update, local_only=True) if typ == Type.SERVICE_OBJECT: @@ -496,14 +496,14 @@ def get_members(self, typ: Type, refs: str | None) -> list[str]: ) return refs.split(fwo_const.LIST_DELIMITER) if refs else [] - def get_flats(self, typ: Type, uid: str) -> list[str]: + def get_flats(self, typ: Type, uid: str) -> set[str]: if typ == Type.NETWORK_OBJECT: return self.group_flats_mapper.get_network_object_flats([uid]) if typ == Type.SERVICE_OBJECT: return self.group_flats_mapper.get_service_object_flats([uid]) return self.group_flats_mapper.get_user_flats([uid]) - def get_prev_flats(self, typ: Type, uid: str) -> list[str]: + def get_prev_flats(self, typ: Type, uid: str) -> set[str]: if typ == Type.NETWORK_OBJECT: return self.prev_group_flats_mapper.get_network_object_flats([uid]) if typ == Type.SERVICE_OBJECT: @@ -648,16 +648,13 @@ def add_group_memberships(self, prev_config: FwConfigNormalized, obj_type: Type) continue member_uids = self.get_members(obj_type, self.get_refs(obj_type, current_config_objects[uid])) prev_member_uids = [] # all members need to be added if group added or changed - prev_flat_member_uids = [] + prev_flat_member_uids: set[str] = set() if uid in prev_config_objects and current_config_objects[uid] == prev_config_objects[uid]: # group not changed -> check for changes in members prev_member_uids = self.get_members(obj_type, self.get_refs(obj_type, prev_config_objects[uid])) prev_flat_member_uids = self.get_prev_flats(obj_type, uid) group_id = self.get_id(obj_type, uid) - if group_id is None: - FWOLogger.error(f"failed to add group memberships: no id found for group uid '{uid}'") - continue self.collect_group_members( group_id, @@ -691,13 +688,13 @@ def collect_flat_group_members( group_id: int, current_config_objects: dict[str, Any], new_group_member_flats: list[dict[str, Any]], - flat_member_uids: list[str], + flat_member_uids: set[str], obj_type: Type, prefix: str, - prev_flat_member_uids: list[str], + prev_flat_member_uids: set[str], prev_config_objects: dict[str, Any], ): - for flat_member_uid in flat_member_uids: + for flat_member_uid in sorted(flat_member_uids): # deterministic order for better debugging and testing if ( flat_member_uid in prev_flat_member_uids and prev_config_objects[flat_member_uid] == current_config_objects[flat_member_uid] @@ -724,10 +721,14 @@ def collect_group_members( prev_member_uids: list[str], prev_config_objects: dict[str, Any], ): + added_member_ids: set[int] = set() for member_uid in member_uids: if member_uid in prev_member_uids and prev_config_objects[member_uid] == current_config_objects[member_uid]: continue # member was not added or changed member_id = self.get_id(obj_type, member_uid) + if member_id in added_member_ids: + continue # avoid duplicate entries for same member and group (e.g. if same member is contained twice) + added_member_ids.add(member_id) new_group_members.append( { f"{prefix}_id": group_id, diff --git a/roles/importer/files/importer/model_controllers/fwconfig_import_rule.py b/roles/importer/files/importer/model_controllers/fwconfig_import_rule.py index 153efc9ca5..324cf0e3d5 100644 --- a/roles/importer/files/importer/model_controllers/fwconfig_import_rule.py +++ b/roles/importer/files/importer/model_controllers/fwconfig_import_rule.py @@ -306,13 +306,15 @@ def get_rule_refs( tos.append((dst_ref, user_ref)) svcs = rule.rule_svc_refs.split(fwo_const.LIST_DELIMITER) if is_prev: - nwobj_resolveds = self.prev_group_flats_mapper.get_network_object_flats([ref[0] for ref in froms + tos]) - svc_resolveds = self.prev_group_flats_mapper.get_service_object_flats(svcs) - user_resolveds = self.prev_group_flats_mapper.get_user_flats(users) + nwobj_resolveds = sorted( + self.prev_group_flats_mapper.get_network_object_flats([ref[0] for ref in froms + tos]) + ) + svc_resolveds = sorted(self.prev_group_flats_mapper.get_service_object_flats(svcs)) + user_resolveds = sorted(self.prev_group_flats_mapper.get_user_flats(users)) else: - nwobj_resolveds = self.group_flats_mapper.get_network_object_flats([ref[0] for ref in froms + tos]) - svc_resolveds = self.group_flats_mapper.get_service_object_flats(svcs) - user_resolveds = self.group_flats_mapper.get_user_flats(users) + nwobj_resolveds = sorted(self.group_flats_mapper.get_network_object_flats([ref[0] for ref in froms + tos])) + svc_resolveds = sorted(self.group_flats_mapper.get_service_object_flats(svcs)) + user_resolveds = sorted(self.group_flats_mapper.get_user_flats(users)) from_zones = rule.rule_src_zone.split(fwo_const.LIST_DELIMITER) if rule.rule_src_zone else [] to_zones = rule.rule_dst_zone.split(fwo_const.LIST_DELIMITER) if rule.rule_dst_zone else [] times = rule.rule_time.split(fwo_const.LIST_DELIMITER) if rule.rule_time else [] diff --git a/roles/importer/files/importer/services/group_flats_mapper.py b/roles/importer/files/importer/services/group_flats_mapper.py index 081d795dd4..8aa5d4a941 100644 --- a/roles/importer/files/importer/services/group_flats_mapper.py +++ b/roles/importer/files/importer/services/group_flats_mapper.py @@ -50,7 +50,7 @@ def init_config( self.service_object_flats = {} self.user_flats = {} - def get_network_object_flats(self, uids: list[str]) -> list[str]: + def get_network_object_flats(self, uids: list[str]) -> set[str]: """ Flatten the network object UIDs to all members, including group objects, and the top-level group object itself. Does not check if the given objects are group objects or not. @@ -59,18 +59,18 @@ def get_network_object_flats(self, uids: list[str]) -> list[str]: uids (list[str]): The list of network object UIDs to flatten. Returns: - list[str]: The flattened network object UIDs. + set[str]: The flattened network object UIDs. """ if self.normalized_config is None: self.log_error(f"{CONFIG_NOT_SET_MESSAGE} - networks") - return [] + return set() all_members: set[str] = set() for uid in uids: members = self.flat_nwobj_members_recursive(uid) if members is not None: all_members.update(members) - return list(all_members) + return all_members def flat_nwobj_members_recursive(self, group_uid: str, recursion_level: int = 0) -> set[str] | None: if recursion_level > MAX_RECURSION_LEVEL: @@ -102,7 +102,7 @@ def get_nwobj(self, group_uid: str) -> NetworkObject | None: nwobj = self.global_normalized_config.network_objects.get(group_uid, None) return nwobj - def get_service_object_flats(self, uids: list[str]) -> list[str]: + def get_service_object_flats(self, uids: list[str]) -> set[str]: """ Flatten the service object UIDs to all members, including group objects, and the top-level group object itself. Does not check if the given objects are group objects or not. @@ -111,18 +111,18 @@ def get_service_object_flats(self, uids: list[str]) -> list[str]: uids (list[str]): The list of service object UIDs to flatten. Returns: - list[str]: The flattened service object UIDs. + set[str]: The flattened service object UIDs. """ if self.normalized_config is None: self.log_error(f"{CONFIG_NOT_SET_MESSAGE} - services") - return [] + return set() all_members: set[str] = set() for uid in uids: members = self.flat_svcobj_members_recursive(uid) if members is not None: all_members.update(members) - return list(all_members) + return all_members def flat_svcobj_members_recursive(self, group_uid: str, recursion_level: int = 0) -> set[str] | None: if recursion_level > MAX_RECURSION_LEVEL: @@ -154,7 +154,7 @@ def get_svcobj(self, group_uid: str) -> ServiceObject | None: svcobj = self.global_normalized_config.service_objects.get(group_uid, None) return svcobj - def get_user_flats(self, uids: list[str]) -> list[str]: + def get_user_flats(self, uids: list[str]) -> set[str]: """ Flatten the user UIDs to all members, including groups, and the top-level group itself. Does not check if the given users are groups or not. @@ -163,18 +163,18 @@ def get_user_flats(self, uids: list[str]) -> list[str]: uids (list[str]): The list of user UIDs to flatten. Returns: - list[str]: The flattened user UIDs. + set[str]: The flattened user UIDs. """ if self.normalized_config is None: self.log_error(f"{CONFIG_NOT_SET_MESSAGE} - users") - return [] + return set() all_members: set[str] = set() for uid in uids: members = self.flat_user_members_recursive(uid) if members is not None: all_members.update(members) - return list(all_members) + return all_members def flat_user_members_recursive(self, group_uid: str, recursion_level: int = 0) -> set[str] | None: if recursion_level > MAX_RECURSION_LEVEL: diff --git a/roles/importer/files/importer/test/test_fwconfig_import_object.py b/roles/importer/files/importer/test/test_fwconfig_import_object.py index e0ed1a65f5..e08da92d3a 100644 --- a/roles/importer/files/importer/test/test_fwconfig_import_object.py +++ b/roles/importer/files/importer/test/test_fwconfig_import_object.py @@ -538,8 +538,8 @@ def test_collect_flat_group_members_empty( new_group_member_flats=new_group_member_flats, obj_type=Type.NETWORK_OBJECT, prev_config_objects={}, - flat_member_uids=[], - prev_flat_member_uids=[], + flat_member_uids=set(), + prev_flat_member_uids=set(), ) # Assert @@ -560,8 +560,8 @@ def test_collect_flat_group_members_no_changes( new_group_member_flats=new_group_member_flats, obj_type=Type.NETWORK_OBJECT, prev_config_objects={"1": {"id": 1, "uid": "1"}}, - flat_member_uids=["1"], - prev_flat_member_uids=["1"], + flat_member_uids={"1"}, + prev_flat_member_uids={"1"}, ) # Assert @@ -592,8 +592,8 @@ def test_collect_flat_group_members_with_changes( "1": {"id": 1, "uid": "1"}, "3": {"id": 3, "uid": "3"}, }, - flat_member_uids=["1", "2"], - prev_flat_member_uids=["1", "3"], + flat_member_uids={"1", "2"}, + prev_flat_member_uids={"1", "3"}, ) # Assert @@ -671,38 +671,6 @@ def test_add_group_memberships_no_group_changes( # Assert fwconfig_import_object.write_member_updates.assert_not_called() - def test_add_group_memberships_no_group_id( - self, - fwconfig_import_object: FwConfigImportObject, - fwconfig_builder: FwConfigBuilder, - mocker: MockerFixture, - ): - # Arrange - mock_logger = mocker.patch("fwo_log.FWOLogger.error") - fwconfig_import_object.normalized_config, _ = fwconfig_builder.build_config( - network_object_count=1, - ) - prev_config, __ = fwconfig_builder.build_config( - network_object_count=1, - ) - fwconfig_import_object.write_member_updates = mocker.Mock() - fwconfig_import_object.uid2id_mapper.get_network_object_id = mocker.Mock(return_value=None) - - # Act - fwconfig_import_object.add_group_memberships( - obj_type=Type.NETWORK_OBJECT, - prev_config=prev_config, - ) - - # Assert - fwconfig_import_object.write_member_updates.assert_not_called() - - assert mock_logger.call_count == 1 - assert ( - mock_logger.call_args[0][0] - == f"failed to add group memberships: no id found for group uid '{next(iter(fwconfig_import_object.normalized_config.network_objects.keys()))}'" - ) - def test_add_group_memberships_with_changes( self, fwconfig_import_object: FwConfigImportObject, @@ -720,7 +688,7 @@ def test_add_group_memberships_with_changes( fwconfig_import_object.write_member_updates = mocker.Mock() fwconfig_import_object.uid2id_mapper.get_network_object_id = mocker.Mock(return_value=1) fwconfig_import_object.prev_group_flats_mapper.get_network_object_flats = mocker.Mock( - return_value=["old-member-uid"] + return_value={"old-member-uid"} ) # Act @@ -769,7 +737,7 @@ def test_add_group_memberships_self_reference_group( fwconfig_import_object.write_member_updates = mocker.Mock() fwconfig_import_object.uid2id_mapper.get_network_object_id = mocker.Mock(return_value=1) fwconfig_import_object.group_flats_mapper.get_network_object_flats = mocker.Mock( - return_value=[group_obj.obj_uid] + return_value={group_obj.obj_uid} ) # Act @@ -799,6 +767,73 @@ def test_add_group_memberships_self_reference_group( "objgrp", ) + def test_add_group_memberships_duplicate_direct_member_sends_no_duplicates( + self, + fwconfig_import_object: FwConfigImportObject, + fwconfig_builder: FwConfigBuilder, + mocker: MockerFixture, + ): + # Arrange + fwconfig_import_object.normalized_config, _ = fwconfig_builder.build_config( + network_object_count=2, + service_object_count=0, + include_gateway=False, + ) + prev_config = fwconfig_builder.build_empty_config() + group_uid, member_uid = list(fwconfig_import_object.normalized_config.network_objects.keys())[:2] + fwconfig_import_object.normalized_config.network_objects[group_uid].obj_typ = "group" + fwconfig_import_object.normalized_config.network_objects[ + group_uid + ].obj_member_refs = f"{member_uid}{LIST_DELIMITER}{member_uid}" + fwconfig_import_object.normalized_config.network_objects[member_uid].obj_typ = "host" + + def fake_get_id(uid: str, _before_update: bool = False): + mapping = { + group_uid: 1, + member_uid: 2, + } + return mapping[uid] + + fwconfig_import_object.import_state.state.import_id = 13 + fwconfig_import_object.uid2id_mapper.get_network_object_id = mocker.Mock(side_effect=fake_get_id) + fwconfig_import_object.group_flats_mapper.get_network_object_flats = mocker.Mock(return_value={member_uid}) + fwconfig_import_object.import_state.api_call.call = mocker.Mock( + return_value={ + "data": { + "insert_objgrp": {"affected_rows": 1}, + "insert_objgrp_flat": {"affected_rows": 1}, + } + } + ) + + # Act + fwconfig_import_object.add_group_memberships( + obj_type=Type.NETWORK_OBJECT, + prev_config=prev_config, + ) + + # Assert + fwconfig_import_object.import_state.api_call.call.assert_called_once() + query_variables = fwconfig_import_object.import_state.api_call.call.call_args.kwargs["query_variables"] + assert query_variables == { + "groups": [ + { + "import_created": 13, + "import_last_seen": 13, + "objgrp_id": 1, + "objgrp_member_id": 2, + } + ], + "groupFlats": [ + { + "import_created": 13, + "import_last_seen": 13, + "objgrp_flat_id": 1, + "objgrp_flat_member_id": 2, + } + ], + } + def test_add_group_memberships_member_changed( self, fwconfig_import_object: FwConfigImportObject, @@ -825,8 +860,8 @@ def fake_get_id(uid: str, _before_update: bool = False): fwconfig_import_object.import_state.state.import_id = 9 fwconfig_import_object.write_member_updates = mocker.Mock() fwconfig_import_object.uid2id_mapper.get_network_object_id = mocker.Mock(side_effect=fake_get_id) - fwconfig_import_object.group_flats_mapper.get_network_object_flats = mocker.Mock(return_value=[member_uid]) - fwconfig_import_object.prev_group_flats_mapper.get_network_object_flats = mocker.Mock(return_value=[member_uid]) + fwconfig_import_object.group_flats_mapper.get_network_object_flats = mocker.Mock(return_value={member_uid}) + fwconfig_import_object.prev_group_flats_mapper.get_network_object_flats = mocker.Mock(return_value={member_uid}) # Act fwconfig_import_object.add_group_memberships( @@ -892,7 +927,7 @@ def fake_get_id(uid: str, _before_update: bool = False): fwconfig_import_object.write_member_updates = mocker.Mock() fwconfig_import_object.uid2id_mapper.get_network_object_id = mocker.Mock(side_effect=fake_get_id) fwconfig_import_object.group_flats_mapper.get_network_object_flats = mocker.Mock( - return_value=[member_uid_one, member_uid_two] + return_value={member_uid_one, member_uid_two} ) # Act @@ -902,37 +937,37 @@ def fake_get_id(uid: str, _before_update: bool = False): ) # Assert - fwconfig_import_object.write_member_updates.assert_called_once_with( - [ - { - "import_created": 11, - "import_last_seen": 11, - "objgrp_id": 1, - "objgrp_member_id": 2, - }, - { - "import_created": 11, - "import_last_seen": 11, - "objgrp_id": 1, - "objgrp_member_id": 3, - }, - ], - [ - { - "import_created": 11, - "import_last_seen": 11, - "objgrp_flat_id": 1, - "objgrp_flat_member_id": 2, - }, - { - "import_created": 11, - "import_last_seen": 11, - "objgrp_flat_id": 1, - "objgrp_flat_member_id": 3, - }, - ], - "objgrp", - ) + fwconfig_import_object.write_member_updates.assert_called_once() + actual_members, actual_flats, actual_prefix = fwconfig_import_object.write_member_updates.call_args.args + assert sorted(actual_members, key=lambda x: x["objgrp_member_id"]) == [ + { + "import_created": 11, + "import_last_seen": 11, + "objgrp_id": 1, + "objgrp_member_id": 2, + }, + { + "import_created": 11, + "import_last_seen": 11, + "objgrp_id": 1, + "objgrp_member_id": 3, + }, + ] + assert sorted(actual_flats, key=lambda x: x["objgrp_flat_member_id"]) == [ + { + "import_created": 11, + "import_last_seen": 11, + "objgrp_flat_id": 1, + "objgrp_flat_member_id": 2, + }, + { + "import_created": 11, + "import_last_seen": 11, + "objgrp_flat_id": 1, + "objgrp_flat_member_id": 3, + }, + ] + assert actual_prefix == "objgrp" class TestFwConfigImportObjectFindRemovedObjects: @@ -1018,7 +1053,7 @@ def test_find_removed_objects_with_changes( removed_flats: list[dict[str, Any]] = [] removed_members: list[dict[str, Any]] = [] fwconfig_import_object.uid2id_mapper.get_network_object_id = mocker.Mock(return_value=1) - fwconfig_import_object.prev_group_flats_mapper.get_network_object_flats = mocker.Mock(return_value=[2]) + fwconfig_import_object.prev_group_flats_mapper.get_network_object_flats = mocker.Mock(return_value={2}) # Act fwconfig_import_object.find_removed_objects( @@ -1085,7 +1120,7 @@ def test_find_removed_objects_no_member_changes( removed_members: list[dict[str, Any]] = [] fwconfig_import_object.uid2id_mapper.get_network_object_id = mocker.Mock(return_value=last_obj_uid) fwconfig_import_object.prev_group_flats_mapper.get_network_object_flats = mocker.Mock( - return_value=[last_obj_uid] + return_value={last_obj_uid} ) # Act @@ -1144,7 +1179,7 @@ def test_remove_outdated_memberships_with_changes_and_success( obj.obj_member_refs = "new-member-uid" fwconfig_import_object.uid2id_mapper.get_network_object_id = mocker.Mock(return_value=1) - fwconfig_import_object.prev_group_flats_mapper.get_network_object_flats = mocker.Mock(return_value=[2]) + fwconfig_import_object.prev_group_flats_mapper.get_network_object_flats = mocker.Mock(return_value={2}) fwconfig_import_object.import_state.api_call.call = mocker.Mock( return_value={ "data": { @@ -1197,7 +1232,7 @@ def test_remove_outdated_memberships_with_changes_and_errors( for obj in prev_config.network_objects.values(): obj.obj_member_refs = "old-member-uid" - fwconfig_import_object.prev_group_flats_mapper.get_network_object_flats = mocker.Mock(return_value=[2]) + fwconfig_import_object.prev_group_flats_mapper.get_network_object_flats = mocker.Mock(return_value={2}) fwconfig_import_object.import_state.api_call.call = mocker.Mock( return_value={ "errors": [ @@ -1240,10 +1275,10 @@ def test_remove_outdated_memberships_with_changes_and_exception( for obj in prev_config.network_objects.values(): obj.obj_member_refs = "old-member-uid" fwconfig_import_object.uid2id_mapper.get_network_object_id = mocker.Mock(return_value=1) - fwconfig_import_object.prev_group_flats_mapper.get_network_object_flats = mocker.Mock(return_value=[2]) + fwconfig_import_object.prev_group_flats_mapper.get_network_object_flats = mocker.Mock(return_value={2}) fwconfig_import_object.import_state.api_call.call = mocker.Mock( return_value={ - "error": "Some unexpected error occurred", + "errors": "Some unexpected error occurred", } ) fwconfig_import_object.import_state.state.import_id = 5 @@ -1259,7 +1294,7 @@ def test_remove_outdated_memberships_with_changes_and_exception( fwconfig_import_object.import_state.api_call.call.assert_called_once() mock_logger.assert_called_once() assert str(mock_logger.call_args[0][0]).startswith( - "failed to remove outdated group memberships for Type.NETWORK_OBJECT: Traceback" + "fwo_api:importNwObject - error in removeOutdatedObjgrpMemberships: Some unexpected error occurred" ) def test_remove_outdated_memberships_group_removed( @@ -1283,7 +1318,7 @@ def fake_get_id(uid: str, _before_update: bool = False): return 10 if uid == group_uid else 20 fwconfig_import_object.uid2id_mapper.get_network_object_id = mocker.Mock(side_effect=fake_get_id) - fwconfig_import_object.prev_group_flats_mapper.get_network_object_flats = mocker.Mock(return_value=[member_uid]) + fwconfig_import_object.prev_group_flats_mapper.get_network_object_flats = mocker.Mock(return_value={member_uid}) fwconfig_import_object.import_state.api_call.call = mocker.Mock( return_value={ "data": { @@ -1339,7 +1374,7 @@ def fake_get_id(uid: str, _before_update: bool = False): fwconfig_import_object.uid2id_mapper.get_network_object_id = mocker.Mock(side_effect=fake_get_id) fwconfig_import_object.prev_group_flats_mapper.get_network_object_flats = mocker.Mock( - return_value=[member_uid_one, member_uid_two] + return_value={member_uid_one, member_uid_two} ) fwconfig_import_object.import_state.api_call.call = mocker.Mock( return_value={ @@ -1358,18 +1393,20 @@ def fake_get_id(uid: str, _before_update: bool = False): ) # Assert - call_args = fwconfig_import_object.import_state.api_call.call.call_args - assert call_args.kwargs["query_variables"] == { - "importId": 12, - "removedMembers": [ - {"_and": [{"objgrp_id": {"_eq": 100}}, {"objgrp_member_id": {"_eq": 200}}]}, - {"_and": [{"objgrp_id": {"_eq": 100}}, {"objgrp_member_id": {"_eq": 300}}]}, - ], - "removedFlats": [ - {"_and": [{"objgrp_flat_id": {"_eq": 100}}, {"objgrp_flat_member_id": {"_eq": 200}}]}, - {"_and": [{"objgrp_flat_id": {"_eq": 100}}, {"objgrp_flat_member_id": {"_eq": 300}}]}, - ], - } + fwconfig_import_object.import_state.api_call.call.assert_called_once() + query_variables = fwconfig_import_object.import_state.api_call.call.call_args.kwargs["query_variables"] + import_id = query_variables["importId"] + actual_members = query_variables["removedMembers"] + actual_flats = query_variables["removedFlats"] + assert import_id == 12 + assert sorted(actual_members, key=lambda x: x["_and"][1]["objgrp_member_id"]["_eq"]) == [ + {"_and": [{"objgrp_id": {"_eq": 100}}, {"objgrp_member_id": {"_eq": 200}}]}, + {"_and": [{"objgrp_id": {"_eq": 100}}, {"objgrp_member_id": {"_eq": 300}}]}, + ] + assert sorted(actual_flats, key=lambda x: x["_and"][1]["objgrp_flat_member_id"]["_eq"]) == [ + {"_and": [{"objgrp_flat_id": {"_eq": 100}}, {"objgrp_flat_member_id": {"_eq": 200}}]}, + {"_and": [{"objgrp_flat_id": {"_eq": 100}}, {"objgrp_flat_member_id": {"_eq": 300}}]}, + ] class TestFwConfigImportObjectGetPrefix: @@ -1420,13 +1457,13 @@ def test_get_prev_flats_network_object( mocker: MockerFixture, ): # Arrange - fwconfig_import_object.prev_group_flats_mapper.get_network_object_flats = mocker.Mock(return_value=[1, 2, 3]) + fwconfig_import_object.prev_group_flats_mapper.get_network_object_flats = mocker.Mock(return_value={1, 2, 3}) # Act flats = fwconfig_import_object.get_prev_flats(Type.NETWORK_OBJECT, "some-uid") # Assert - assert flats == [1, 2, 3] + assert flats == {1, 2, 3} def test_get_prev_flats_service_object( self, @@ -1434,13 +1471,13 @@ def test_get_prev_flats_service_object( mocker: MockerFixture, ): # Arrange - fwconfig_import_object.prev_group_flats_mapper.get_service_object_flats = mocker.Mock(return_value=[4, 5, 6]) + fwconfig_import_object.prev_group_flats_mapper.get_service_object_flats = mocker.Mock(return_value={4, 5, 6}) # Act flats = fwconfig_import_object.get_prev_flats(Type.SERVICE_OBJECT, "some-uid") # Assert - assert flats == [4, 5, 6] + assert flats == {4, 5, 6} def test_get_prev_flats_user_object( self, @@ -1448,13 +1485,13 @@ def test_get_prev_flats_user_object( mocker: MockerFixture, ): # Arrange - fwconfig_import_object.prev_group_flats_mapper.get_user_flats = mocker.Mock(return_value=[7, 8, 9]) + fwconfig_import_object.prev_group_flats_mapper.get_user_flats = mocker.Mock(return_value={7, 8, 9}) # Act flats = fwconfig_import_object.get_prev_flats(Type.USER, "some-uid") # Assert - assert flats == [7, 8, 9] + assert flats == {7, 8, 9} class TestFwConfigImportObjectGetFlats: @@ -1464,13 +1501,13 @@ def test_get_flats_network_object( mocker: MockerFixture, ): # Arrange - fwconfig_import_object.group_flats_mapper.get_network_object_flats = mocker.Mock(return_value=[1, 2, 3]) + fwconfig_import_object.group_flats_mapper.get_network_object_flats = mocker.Mock(return_value={1, 2, 3}) # Act flats = fwconfig_import_object.get_flats(Type.NETWORK_OBJECT, "some-uid") # Assert - assert flats == [1, 2, 3] + assert flats == {1, 2, 3} def test_get_flats_service_object( self, @@ -1478,13 +1515,13 @@ def test_get_flats_service_object( mocker: MockerFixture, ): # Arrange - fwconfig_import_object.group_flats_mapper.get_service_object_flats = mocker.Mock(return_value=[4, 5, 6]) + fwconfig_import_object.group_flats_mapper.get_service_object_flats = mocker.Mock(return_value={4, 5, 6}) # Act flats = fwconfig_import_object.get_flats(Type.SERVICE_OBJECT, "some-uid") # Assert - assert flats == [4, 5, 6] + assert flats == {4, 5, 6} def test_get_flats_user_object( self, @@ -1492,13 +1529,13 @@ def test_get_flats_user_object( mocker: MockerFixture, ): # Arrange - fwconfig_import_object.group_flats_mapper.get_user_flats = mocker.Mock(return_value=[7, 8, 9]) + fwconfig_import_object.group_flats_mapper.get_user_flats = mocker.Mock(return_value={7, 8, 9}) # Act flats = fwconfig_import_object.get_flats(Type.USER, "some-uid") # Assert - assert flats == [7, 8, 9] + assert flats == {7, 8, 9} class TestFwConfigImportObjectGetMembers: