From 0390076bfdeb122b33437a55a08ade9880127deb Mon Sep 17 00:00:00 2001 From: PRANAV THUBE Date: Wed, 4 Mar 2026 20:06:07 +0530 Subject: [PATCH] ipatests: Extend netgroup test coverage. Add new test cases for netgroup plugin: netgroup_add: - Negative tests for space in nisdomain/description - Invalid usercategory/hostcategory values - Invalid addattr/setattr attributes - Positive tests for custom nisdomain, usercat=all, hostcat=all, combined usercat+hostcat, and externalHost via addattr netgroup_mod: - Modify nisdomain, usercategory, hostcategory, description - setattr/addattr/delattr for description and externalHost - Negative tests for invalid values and disallowed attributes netgroup_add_member: - Negative tests for non-existent user, group, hostgroup members - Add member to non-existent netgroup netgroup_remove_member: - Remove member from non-existent netgroup netgroup_find: - Search by description and nisdomain - Negative searches returning zero results Integration tests: - Managed netgroups plugin (ipa-managed-entries) - Find with --in-netgroups/--not-in-netgroups across entities - CLI-specific options (--pkey-only, --sizelimit, --timelimit) - Complex multi-host/DNS setup scenarios Related: https://pagure.io/freeipa/issue/9952 Signed-off-by: Pranav Thube pthube@redhat.com Reviewed-By: Florence Blanc-Renaud Reviewed-By: David Hanina Reviewed-By: Carla Martinez --- ipatests/pytest_ipa/integration/tasks.py | 8 +- ipatests/test_integration/test_netgroup.py | 211 +- ipatests/test_xmlrpc/test_netgroup_plugin.py | 2091 ++++++++++++++++-- 3 files changed, 2059 insertions(+), 251 deletions(-) diff --git a/ipatests/pytest_ipa/integration/tasks.py b/ipatests/pytest_ipa/integration/tasks.py index d9f142794521ced8f96c2af46b1d2fb59cdcad87..ee2befd6998da3b8035e4e015d7528b5a9676a7b 100755 --- a/ipatests/pytest_ipa/integration/tasks.py +++ b/ipatests/pytest_ipa/integration/tasks.py @@ -2272,9 +2272,9 @@ def user_add(host, login, first='test', last='user', extra_args=(), return host.run_command(cmd, stdin_text=stdin_text) -def user_del(host, login): +def user_del(host, login, raiseonerr=True): cmd = ["ipa", "user-del", login] - return host.run_command(cmd) + return host.run_command(cmd, raiseonerr=raiseonerr) def group_add(host, groupname, extra_args=()): @@ -2285,11 +2285,11 @@ def group_add(host, groupname, extra_args=()): return host.run_command(cmd) -def group_del(host, groupname): +def group_del(host, groupname, raiseonerr=True): cmd = [ "ipa", "group-del", groupname, ] - return host.run_command(cmd) + return host.run_command(cmd, raiseonerr=raiseonerr) def group_add_member(host, groupname, users=None, diff --git a/ipatests/test_integration/test_netgroup.py b/ipatests/test_integration/test_netgroup.py index 5fae9e03f7b261e397c08217ec479e9380563bef..86b156a8332745063170ab8436a8a89a3752f2c1 100644 --- a/ipatests/test_integration/test_netgroup.py +++ b/ipatests/test_integration/test_netgroup.py @@ -5,7 +5,20 @@ import pytest from ipatests.test_integration.base import IntegrationTest -from ipatests.pytest_ipa.integration.tasks import clear_sssd_cache +from ipatests.pytest_ipa.integration import tasks + +# In-netgroups test entities +# *_MEMBER entities are added to INNG_NG_PARENT netgroup +# *_NONMEMBER entities are NOT added to any netgroup +INNG_USER_MEMBER = 'inng_user_member' +INNG_USER_NONMEMBER = 'inng_user_nonmember' +INNG_GRP_MEMBER = 'inng_grp_member' +INNG_GRP_NONMEMBER = 'inng_grp_nonmember' +INNG_HG_MEMBER = 'inng_hg_member' +INNG_HG_NONMEMBER = 'inng_hg_nonmember' +INNG_NG_PARENT = 'inng_ng_parent' +INNG_NG_MEMBER = 'inng_ng_member' +INNG_NG_NONMEMBER = 'inng_ng_nonmember' test_data = [] @@ -56,16 +69,14 @@ def three_netgroups(request): class TestNetgroups(IntegrationTest): - """ - Test Netgroups - """ + """Test Netgroups - nested, managed, find, show, delete operations.""" topology = 'line' def check_users_in_netgroups(self): """Check if users are in groups, no nested things""" master = self.master - clear_sssd_cache(master) + tasks.clear_sssd_cache(master) for d in test_data: result = master.run_command(['getent', 'passwd', @@ -86,7 +97,7 @@ class TestNetgroups(IntegrationTest): def check_nested_netgroup_hierarchy(self): """Check if nested netgroups hierarchy is complete""" master = self.master - clear_sssd_cache(master) + tasks.clear_sssd_cache(master) for d in test_data: result = master.run_command(['getent', 'netgroup', d['netgroup']], @@ -135,7 +146,7 @@ class TestNetgroups(IntegrationTest): test_data[1]['netgroup']], raiseonerr=False) assert result.returncode == 0 - clear_sssd_cache(master) + tasks.clear_sssd_cache(master) result = master.run_command(['getent', 'netgroup', test_data[1]['netgroup']], @@ -158,7 +169,7 @@ class TestNetgroups(IntegrationTest): test_data[2]['netgroup']], raiseonerr=False) assert result.returncode == 0 - clear_sssd_cache(master) + tasks.clear_sssd_cache(master) result = master.run_command(['getent', 'netgroup', test_data[2]['netgroup']], @@ -167,3 +178,187 @@ class TestNetgroups(IntegrationTest): assert trinity[0] not in result.stdout_text assert trinity[1] not in result.stdout_text assert trinity[2] in result.stdout_text + + # --- Managed Netgroups Tests --- + + def test_managed_netgroup_lifecycle(self): + """Test managed netgroup created/deleted with hostgroup.""" + master = self.master + # Enable NGP plugin + master.run_command( + ['ipa-managed-entries', '--entry=NGP Definition', 'enable'], + raiseonerr=False + ) + # Add hostgroup - managed netgroup should be created + tasks.hostgroup_add(master, 'mng_testgrp', ('--desc=test',)) + master.run_command( + ['ipa', 'netgroup-find', '--managed', 'mng_testgrp'] + ) + + # Delete hostgroup - managed netgroup should be deleted + tasks.hostgroup_del(master, 'mng_testgrp') + # ipa *-find returns exit code 1 when 0 results found + result = master.run_command( + ['ipa', 'netgroup-find', '--managed', 'mng_testgrp'], + raiseonerr=False + ) + assert '0 netgroups matched' in result.stdout_text + + def test_cannot_delete_managed_netgroup(self): + """Deleting managed netgroup directly should fail.""" + master = self.master + master.run_command( + ['ipa-managed-entries', '--entry=NGP Definition', 'enable'], + raiseonerr=False + ) + tasks.hostgroup_add(master, 'mng_nodelete', ('--desc=test',)) + try: + result = master.run_command( + ['ipa', 'netgroup-del', 'mng_nodelete'], raiseonerr=False + ) + assert result.returncode != 0 + assert 'Deleting a managed entry is not allowed' in \ + result.stderr_text + finally: + tasks.hostgroup_del(master, 'mng_nodelete', raiseonerr=False) + + # --- In-Netgroups Tests for Various Entity Types --- + + @pytest.fixture(scope='class') + def in_netgroups_setup(self, request): + """Setup for --in-netgroups tests across entity types.""" + master = self.master + domain = master.domain.name + innghost1 = f'innghost1.{domain}' + innghost2 = f'innghost2.{domain}' + + # Register cleanup FIRST so it runs even if setup fails + def cleanup(): + for ng in [INNG_NG_PARENT, INNG_NG_MEMBER, INNG_NG_NONMEMBER]: + master.run_command( + ['ipa', 'netgroup-del', ng], raiseonerr=False + ) + tasks.hostgroup_del(master, INNG_HG_MEMBER, raiseonerr=False) + tasks.hostgroup_del(master, INNG_HG_NONMEMBER, raiseonerr=False) + tasks.host_del(master, innghost1, raiseonerr=False) + tasks.host_del(master, innghost2, raiseonerr=False) + tasks.group_del(master, INNG_GRP_MEMBER, raiseonerr=False) + tasks.group_del(master, INNG_GRP_NONMEMBER, raiseonerr=False) + tasks.user_del(master, INNG_USER_MEMBER, raiseonerr=False) + tasks.user_del(master, INNG_USER_NONMEMBER, raiseonerr=False) + request.addfinalizer(cleanup) + + # Create entities + tasks.user_add(master, INNG_USER_MEMBER) + tasks.user_add(master, INNG_USER_NONMEMBER) + tasks.group_add(master, INNG_GRP_MEMBER, ('--desc=test',)) + tasks.group_add(master, INNG_GRP_NONMEMBER, ('--desc=test',)) + tasks.host_add(master, innghost1, '--force') + tasks.host_add(master, innghost2, '--force') + tasks.hostgroup_add(master, INNG_HG_MEMBER, ('--desc=test',)) + tasks.hostgroup_add(master, INNG_HG_NONMEMBER, ('--desc=test',)) + + for ng in [INNG_NG_PARENT, INNG_NG_MEMBER, INNG_NG_NONMEMBER]: + master.run_command(['ipa', 'netgroup-add', ng, '--desc=test']) + + # Add members to parent netgroup only + master.run_command(['ipa', 'netgroup-add-member', INNG_NG_PARENT, + f'--users={INNG_USER_MEMBER}', + f'--groups={INNG_GRP_MEMBER}', + f'--hosts={innghost1}', + f'--hostgroups={INNG_HG_MEMBER}', + f'--netgroups={INNG_NG_MEMBER}']) + + def test_in_netgroups_across_entities(self, in_netgroups_setup): + """Test --in-netgroups and --not-in-netgroups for all entity types.""" + master = self.master + domain = master.domain.name + + entity_tests = [ + ('user-find', INNG_USER_MEMBER, INNG_USER_NONMEMBER), + ('group-find', INNG_GRP_MEMBER, INNG_GRP_NONMEMBER), + ('host-find', f'innghost1.{domain}', f'innghost2.{domain}'), + ('hostgroup-find', INNG_HG_MEMBER, INNG_HG_NONMEMBER), + ('netgroup-find', INNG_NG_MEMBER, INNG_NG_NONMEMBER), + ] + + for cmd, member, non_member in entity_tests: + # Test --in-netgroups + result = master.run_command( + ['ipa', cmd, f'--in-netgroups={INNG_NG_PARENT}'] + ) + assert member in result.stdout_text, \ + f"--in-netgroups failed for {cmd}" + assert non_member not in result.stdout_text + + # Test --not-in-netgroups + result = master.run_command( + ['ipa', cmd, f'--not-in-netgroups={INNG_NG_PARENT}'] + ) + assert non_member in result.stdout_text, \ + f"--not-in-netgroups failed for {cmd}" + + def test_removed_member_not_in_netgroups(self): + """Verify removed member no longer appears in --in-netgroups.""" + master = self.master + user = 'removal_test_user' + netgroup = 'removal_test_ng' + + try: + tasks.user_add(master, user) + master.run_command(['ipa', 'netgroup-add', netgroup]) + master.run_command([ + 'ipa', 'netgroup-add-member', netgroup, f'--users={user}' + ]) + + # Verify user is in netgroup + result = master.run_command( + ['ipa', 'user-find', f'--in-netgroups={netgroup}'] + ) + assert user in result.stdout_text + + # Remove user and verify not in netgroup + master.run_command([ + 'ipa', 'netgroup-remove-member', netgroup, f'--users={user}' + ]) + result = master.run_command( + ['ipa', 'user-find', f'--in-netgroups={netgroup}'], + raiseonerr=False + ) + assert user not in result.stdout_text + + finally: + master.run_command( + ['ipa', 'netgroup-del', netgroup], raiseonerr=False) + tasks.user_del(master, user, raiseonerr=False) + + def test_delete_multiple_netgroups(self): + """Delete multiple netgroups and verify they're deleted.""" + master = self.master + + try: + # Create multiple netgroups + for i in range(1, 4): + master.run_command( + ['ipa', 'netgroup-add', f'del_ng{i}', '--desc=test'] + ) + + # Delete all at once + master.run_command( + ['ipa', 'netgroup-del', 'del_ng1', 'del_ng2', 'del_ng3'] + ) + + # Verify all deleted + for i in range(1, 4): + result = master.run_command( + ['ipa', 'netgroup-show', f'del_ng{i}'], raiseonerr=False + ) + assert result.returncode != 0 + assert 'netgroup not found' in result.stderr_text + + finally: + # Cleanup: ensure netgroups are deleted even if test fails + for i in range(1, 4): + master.run_command( + ['ipa', 'netgroup-del', f'del_ng{i}'], raiseonerr=False + ) diff --git a/ipatests/test_xmlrpc/test_netgroup_plugin.py b/ipatests/test_xmlrpc/test_netgroup_plugin.py index 3f1fc0bc19e258505b6dcf08becd6a402bdd0e58..bee3e3f8e02d07e0794c66a03ec22d78489b37c4 100644 --- a/ipatests/test_xmlrpc/test_netgroup_plugin.py +++ b/ipatests/test_xmlrpc/test_netgroup_plugin.py @@ -62,6 +62,27 @@ invalidnisdomain1=u'domain1,domain2' invalidnisdomain2=u'+invalidnisdomain' invalidhost=u'+invalid&host' +netgroup_nisdomain = 'netgroup_nisdomain' +netgroup_usercat = 'netgroup_usercat' +netgroup_hostcat = 'netgroup_hostcat' +netgroup_usercat_hostcat = 'netgroup_usercat_hostcat' +netgroup_exthost = 'netgroup_exthost' +netgroup_usercat_mod = 'netgroup_usercat_mod' +netgroup_hostcat_mod = 'netgroup_hostcat_mod' +custom_nisdomain = 'testnis.dom' +external_host = 'ipaqatesthost' + +# Entities for netgroup-find tests +fnd_ng1 = 'fndng1' +fnd_ng2 = 'fndng2' +fnd_ng3 = 'fndng3' +fnd_user1 = 'fnduser1' +fnd_user2 = 'fnduser2' +fnd_group = 'fndgroup' +fnd_host = 'fndhost1.%s' % api.env.domain +fnd_hostgroup = 'fndhostgroup' +fnd_nisdomain = 'testdomain' + @pytest.mark.tier1 class test_netgroup(Declarative): @@ -72,11 +93,28 @@ class test_netgroup(Declarative): cleanup_commands = [ ('netgroup_del', [netgroup1], {}), ('netgroup_del', [netgroup2], {}), + ('netgroup_del', [netgroup_single], {}), + ('netgroup_del', [netgroup_nisdomain], {}), + ('netgroup_del', [netgroup_usercat], {}), + ('netgroup_del', [netgroup_hostcat], {}), + ('netgroup_del', [netgroup_usercat_hostcat], {}), + ('netgroup_del', [netgroup_exthost], {}), + ('netgroup_del', [netgroup_usercat_mod], {}), + ('netgroup_del', [netgroup_hostcat_mod], {}), ('host_del', [host1], {}), ('hostgroup_del', [hostgroup1], {}), ('user_del', [user1], {}), ('user_del', [user2], {}), ('group_del', [group1], {}), + # Cleanup for netgroup-find tests + ('netgroup_del', [fnd_ng1], {}), + ('netgroup_del', [fnd_ng2], {}), + ('netgroup_del', [fnd_ng3], {}), + ('hostgroup_del', [fnd_hostgroup], {}), + ('host_del', [fnd_host], {}), + ('group_del', [fnd_group], {}), + ('user_del', [fnd_user1], {}), + ('user_del', [fnd_user2], {}), ] tests=[ @@ -133,6 +171,106 @@ class test_netgroup(Declarative): ), + dict( + desc='Test netgroup add with space in nisdomain', + command=( + 'netgroup_add', [netgroup1], + dict(description='Test', nisdomainname=' ') + ), + expected=errors.ValidationError( + name='nisdomain', + error='may only include letters, numbers, _, -, and .'), + ), + + + dict( + desc='Test netgroup add with space in description', + command=( + 'netgroup_add', [netgroup1], + dict(description=' ') + ), + expected=errors.ValidationError( + name='desc', + error='Leading and trailing spaces are not allowed'), + ), + + + dict( + desc='Test netgroup add with invalid usercat', + command=( + 'netgroup_add', [netgroup1], + dict(description='Test', usercategory='badcat') + ), + expected=errors.ValidationError( + name='usercat', error="must be 'all'"), + ), + + + dict( + desc='Test netgroup add with space for usercat', + command=( + 'netgroup_add', [netgroup1], + dict(description='Test', usercategory=' ') + ), + expected=errors.ValidationError( + name='usercat', error="must be 'all'"), + ), + + + dict( + desc='Test netgroup add with invalid hostcat', + command=( + 'netgroup_add', [netgroup1], + dict(description='Test', hostcategory='badcat') + ), + expected=errors.ValidationError( + name='hostcat', error="must be 'all'"), + ), + + + dict( + desc='Test netgroup add with space for hostcat', + command=( + 'netgroup_add', [netgroup1], + dict(description='Test', hostcategory=' ') + ), + expected=errors.ValidationError( + name='hostcat', error="must be 'all'"), + ), + + + dict( + desc='Test netgroup add with both desc and addattr description', + command=( + 'netgroup_add', [netgroup1], + dict(description='Test', addattr='description=duplicate') + ), + expected=errors.OnlyOneValueAllowed(attr='description'), + ), + + + dict( + desc='Test netgroup add with invalid setattr attribute', + command=( + 'netgroup_add', [netgroup1], + dict(description='Test', setattr='badattr=somevalue') + ), + expected=errors.ObjectclassViolation( + info='attribute "badattr" not allowed'), + ), + + + dict( + desc='Test netgroup add with invalid addattr attribute', + command=( + 'netgroup_add', [netgroup1], + dict(description='Test', addattr='badattr=somevalue') + ), + expected=errors.ObjectclassViolation( + info='attribute "badattr" not allowed'), + ), + + dict( desc='Create %r' % netgroup1, command=('netgroup_add', [netgroup1], @@ -204,6 +342,178 @@ class test_netgroup(Declarative): ), + dict( + desc='Create netgroup %r with custom nisdomain' % ( + netgroup_nisdomain), + command=( + 'netgroup_add', [netgroup_nisdomain], + dict(description='Test with custom nisdomain', + nisdomainname=custom_nisdomain) + ), + expected=dict( + value=netgroup_nisdomain, + summary='Added netgroup "%s"' % netgroup_nisdomain, + result=dict( + dn=fuzzy_netgroupdn, + cn=[netgroup_nisdomain], + objectclass=objectclasses.netgroup, + description=['Test with custom nisdomain'], + nisdomainname=[custom_nisdomain], + ipauniqueid=[fuzzy_uuid], + ), + ), + ), + + dict( + desc='Delete %r' % netgroup_nisdomain, + command=('netgroup_del', [netgroup_nisdomain], {}), + expected=dict( + value=[netgroup_nisdomain], + summary='Deleted netgroup "%s"' % netgroup_nisdomain, + result=dict(failed=[]), + ), + ), + + + dict( + desc='Create netgroup %r with usercat=all' % netgroup_usercat, + command=( + 'netgroup_add', [netgroup_usercat], + dict(description='Test with usercat all', + nisdomainname=custom_nisdomain, usercategory='all') + ), + expected=dict( + value=netgroup_usercat, + summary='Added netgroup "%s"' % netgroup_usercat, + result=dict( + dn=fuzzy_netgroupdn, + cn=[netgroup_usercat], + objectclass=objectclasses.netgroup, + description=['Test with usercat all'], + nisdomainname=[custom_nisdomain], + usercategory=['all'], + ipauniqueid=[fuzzy_uuid], + ), + ), + ), + + dict( + desc='Delete %r' % netgroup_usercat, + command=('netgroup_del', [netgroup_usercat], {}), + expected=dict( + value=[netgroup_usercat], + summary='Deleted netgroup "%s"' % netgroup_usercat, + result=dict(failed=[]), + ), + ), + + + dict( + desc='Create netgroup %r with hostcat=all' % netgroup_hostcat, + command=( + 'netgroup_add', [netgroup_hostcat], + dict(description='Test with hostcat all', + nisdomainname=custom_nisdomain, hostcategory='all') + ), + expected=dict( + value=netgroup_hostcat, + summary='Added netgroup "%s"' % netgroup_hostcat, + result=dict( + dn=fuzzy_netgroupdn, + cn=[netgroup_hostcat], + objectclass=objectclasses.netgroup, + description=['Test with hostcat all'], + nisdomainname=[custom_nisdomain], + hostcategory=['all'], + ipauniqueid=[fuzzy_uuid], + ), + ), + ), + + dict( + desc='Delete %r' % netgroup_hostcat, + command=('netgroup_del', [netgroup_hostcat], {}), + expected=dict( + value=[netgroup_hostcat], + summary='Deleted netgroup "%s"' % netgroup_hostcat, + result=dict(failed=[]), + ), + ), + + + dict( + desc='Create netgroup %r with usercat/hostcat=all' % ( + netgroup_usercat_hostcat), + command=( + 'netgroup_add', [netgroup_usercat_hostcat], + dict(description='Test with usercat and hostcat all', + nisdomainname=custom_nisdomain, + usercategory='all', hostcategory='all') + ), + expected=dict( + value=netgroup_usercat_hostcat, + summary='Added netgroup "%s"' % netgroup_usercat_hostcat, + result=dict( + dn=fuzzy_netgroupdn, + cn=[netgroup_usercat_hostcat], + objectclass=objectclasses.netgroup, + description=['Test with usercat and hostcat all'], + nisdomainname=[custom_nisdomain], + usercategory=['all'], + hostcategory=['all'], + ipauniqueid=[fuzzy_uuid], + ), + ), + ), + + dict( + desc='Delete %r' % netgroup_usercat_hostcat, + command=('netgroup_del', [netgroup_usercat_hostcat], {}), + expected=dict( + value=[netgroup_usercat_hostcat], + summary='Deleted netgroup "%s"' % netgroup_usercat_hostcat, + result=dict(failed=[]), + ), + ), + + + dict( + desc='Create netgroup %r with externalHost' % netgroup_exthost, + command=( + 'netgroup_add', [netgroup_exthost], + dict(description='Test with externalHost', + nisdomainname=custom_nisdomain, + usercategory='all', hostcategory='all', + addattr='externalHost=%s' % external_host) + ), + expected=dict( + value=netgroup_exthost, + summary='Added netgroup "%s"' % netgroup_exthost, + result=dict( + dn=fuzzy_netgroupdn, + cn=[netgroup_exthost], + objectclass=objectclasses.netgroup, + description=['Test with externalHost'], + nisdomainname=[custom_nisdomain], + usercategory=['all'], + hostcategory=['all'], + externalhost=[external_host], + ipauniqueid=[fuzzy_uuid], + ), + ), + ), + + dict( + desc='Delete %r' % netgroup_exthost, + command=('netgroup_del', [netgroup_exthost], {}), + expected=dict( + value=[netgroup_exthost], + summary='Deleted netgroup "%s"' % netgroup_exthost, + result=dict(failed=[]), + ), + ), + + dict( desc='Try to create duplicate %r' % netgroup1, command=('netgroup_add', [netgroup1], @@ -628,6 +938,124 @@ class test_netgroup(Declarative): ), + dict( + desc='Add non-existent user to netgroup %r' % netgroup1, + command=( + 'netgroup_add_member', [netgroup1], + dict(user='notfounduser') + ), + expected=dict( + completed=0, + failed=dict( + member=dict( + netgroup=tuple(), + ), + memberuser=dict( + group=tuple(), + user=[('notfounduser', 'no such entry')], + ), + memberhost=dict( + hostgroup=tuple(), + host=tuple(), + ), + ), + result={ + 'dn': fuzzy_netgroupdn, + 'memberhost_host': (host1,), + 'memberhost_hostgroup': (hostgroup1,), + 'memberuser_user': (user1,), + 'memberuser_group': (group1,), + 'member_netgroup': (netgroup2,), + 'cn': [netgroup1], + 'description': ['Test netgroup 1'], + 'nisdomainname': ['%s' % api.env.domain], + }, + ), + ), + + + dict( + desc='Add non-existent group to netgroup %r' % netgroup1, + command=( + 'netgroup_add_member', [netgroup1], + dict(group='notfoundgroup') + ), + expected=dict( + completed=0, + failed=dict( + member=dict( + netgroup=tuple(), + ), + memberuser=dict( + group=[('notfoundgroup', 'no such entry')], + user=tuple(), + ), + memberhost=dict( + hostgroup=tuple(), + host=tuple(), + ), + ), + result={ + 'dn': fuzzy_netgroupdn, + 'memberhost_host': (host1,), + 'memberhost_hostgroup': (hostgroup1,), + 'memberuser_user': (user1,), + 'memberuser_group': (group1,), + 'member_netgroup': (netgroup2,), + 'cn': [netgroup1], + 'description': ['Test netgroup 1'], + 'nisdomainname': ['%s' % api.env.domain], + }, + ), + ), + + + dict( + desc='Add non-existent hostgroup to netgroup %r' % netgroup1, + command=( + 'netgroup_add_member', [netgroup1], + dict(hostgroup='notfoundhg') + ), + expected=dict( + completed=0, + failed=dict( + member=dict( + netgroup=tuple(), + ), + memberuser=dict( + group=tuple(), + user=tuple(), + ), + memberhost=dict( + hostgroup=[('notfoundhg', 'no such entry')], + host=tuple(), + ), + ), + result={ + 'dn': fuzzy_netgroupdn, + 'memberhost_host': (host1,), + 'memberhost_hostgroup': (hostgroup1,), + 'memberuser_user': (user1,), + 'memberuser_group': (group1,), + 'member_netgroup': (netgroup2,), + 'cn': [netgroup1], + 'description': ['Test netgroup 1'], + 'nisdomainname': ['%s' % api.env.domain], + }, + ), + ), + + + dict( + desc='Add member to non-existent netgroup', + command=( + 'netgroup_add_member', ['notfoundnetgroup'], dict(user=user1) + ), + expected=errors.NotFound( + reason='notfoundnetgroup: netgroup not found'), + ), + + dict( desc='Add duplicate user %r to netgroup %r' % (user1, netgroup1), command=( @@ -1035,358 +1463,1543 @@ class test_netgroup(Declarative): dict( - desc='Update %r' % netgroup1, - command=('netgroup_mod', [netgroup1], - dict(description=u'Updated netgroup 1') + desc='Search for %r by description' % netgroup1, + command=( + 'netgroup_find', [], + dict(description='Test netgroup 1') ), expected=dict( - value=netgroup1, - summary=u'Modified netgroup "%s"' % netgroup1, - result={ - 'memberhost_host': (host1,), - 'memberhost_hostgroup': (hostgroup1,), - 'memberuser_user': (user1,), - 'memberuser_group': (group1,), - 'member_netgroup': (netgroup2,), + count=1, + truncated=False, + summary=u'1 netgroup matched', + result=[ + { + 'dn': fuzzy_netgroupdn, 'cn': [netgroup1], - 'description': [u'Updated netgroup 1'], - 'nisdomainname': [u'%s' % api.env.domain], + 'description': ['Test netgroup 1'], + 'nisdomainname': ['%s' % api.env.domain], 'externalhost': [unknown_host], - }, + }, + ], ), ), dict( - desc='Remove host %r from netgroup %r' % (host1, netgroup1), + desc='Search for netgroups by nisdomain', command=( - 'netgroup_remove_member', [netgroup1], dict(host=host1) + 'netgroup_find', [], + dict(nisdomainname='%s' % api.env.domain) ), expected=dict( - completed=1, - failed=dict( - member=dict( - netgroup=tuple(), - ), - memberuser=dict( - group=tuple(), - user=tuple(), - ), - memberhost=dict( - hostgroup=tuple(), - host=tuple(), - ), - ), - result={ + count=2, + truncated=False, + summary='2 netgroups matched', + result=[ + { 'dn': fuzzy_netgroupdn, - 'memberhost_hostgroup': (hostgroup1,), - 'memberuser_user': (user1,), - 'memberuser_group': (group1,), - 'member_netgroup': (netgroup2,), 'cn': [netgroup1], - 'description': [u'Updated netgroup 1'], - 'nisdomainname': [u'%s' % api.env.domain], + 'description': ['Test netgroup 1'], + 'nisdomainname': ['%s' % api.env.domain], 'externalhost': [unknown_host], - }, + }, + { + 'dn': fuzzy_netgroupdn, + 'cn': [netgroup2], + 'description': ['Test netgroup 2'], + 'nisdomainname': ['%s' % api.env.domain], + }, + ], ), ), dict( - desc='Remove hostgroup %r from netgroup %r' % (hostgroup1, netgroup1), - command=( - 'netgroup_remove_member', [netgroup1], dict(hostgroup=hostgroup1) + desc='Search with non-existent criteria returns zero', + command=('netgroup_find', ['doesnotexist'], {}), + expected=dict( + count=0, + truncated=False, + summary='0 netgroups matched', + result=[], + ), + ), + + + dict( + desc='Search with non-existent description returns zero', + command=('netgroup_find', [], dict(description='baddesc')), + expected=dict( + count=0, + truncated=False, + summary='0 netgroups matched', + result=[], ), + ), + + + dict( + desc='Search with non-existent nisdomain returns zero', + command=('netgroup_find', [], dict(nisdomainname='baddomain')), expected=dict( - completed=1, - failed=dict( - member=dict( - netgroup=tuple(), - ), - memberuser=dict( - group=tuple(), - user=tuple(), - ), - memberhost=dict( - hostgroup=tuple(), - host=tuple(), - ), - ), + count=0, + truncated=False, + summary='0 netgroups matched', + result=[], + ), + ), + + + dict( + desc='Update %r' % netgroup1, + command=('netgroup_mod', [netgroup1], + dict(description='Updated netgroup 1')), + expected=dict( + value=netgroup1, + summary='Modified netgroup "%s"' % netgroup1, result={ - 'dn': fuzzy_netgroupdn, - 'memberuser_user': (user1,), - 'memberuser_group': (group1,), - 'member_netgroup': (netgroup2,), - 'cn': [netgroup1], - 'description': [u'Updated netgroup 1'], - 'nisdomainname': [u'%s' % api.env.domain], - 'externalhost': [unknown_host], + 'memberhost_host': (host1,), + 'memberhost_hostgroup': (hostgroup1,), + 'memberuser_user': (user1,), + 'memberuser_group': (group1,), + 'member_netgroup': (netgroup2,), + 'cn': [netgroup1], + 'description': ['Updated netgroup 1'], + 'nisdomainname': ['%s' % api.env.domain], + 'externalhost': [unknown_host], }, ), ), dict( - desc='Remove user %r from netgroup %r' % (user1, netgroup1), + desc='Modify nisdomain of %r' % netgroup1, command=( - 'netgroup_remove_member', [netgroup1], dict(user=user1) + 'netgroup_mod', [netgroup1], + dict(nisdomainname='newnisdom1') ), expected=dict( - completed=1, - failed=dict( - member=dict( - netgroup=tuple(), - ), - memberuser=dict( - group=tuple(), - user=tuple(), - ), - memberhost=dict( - hostgroup=tuple(), - host=tuple(), - ), - ), + value=netgroup1, + summary='Modified netgroup "%s"' % netgroup1, result={ - 'dn': fuzzy_netgroupdn, - 'memberuser_group': (group1,), - 'member_netgroup': (netgroup2,), - 'cn': [netgroup1], - 'description': [u'Updated netgroup 1'], - 'nisdomainname': [u'%s' % api.env.domain], - 'externalhost': [unknown_host], + 'memberhost_host': (host1,), + 'memberhost_hostgroup': (hostgroup1,), + 'memberuser_user': (user1,), + 'memberuser_group': (group1,), + 'member_netgroup': (netgroup2,), + 'cn': [netgroup1], + 'description': ['Updated netgroup 1'], + 'nisdomainname': ['newnisdom1'], + 'externalhost': [unknown_host], }, ), ), dict( - desc='Remove group %r from netgroup %r' % (group1, netgroup1), + desc='Restore nisdomain of %r' % netgroup1, command=( - 'netgroup_remove_member', [netgroup1], dict(group=group1) + 'netgroup_mod', [netgroup1], + dict(nisdomainname='%s' % api.env.domain) ), expected=dict( - completed=1, - failed=dict( - member=dict( - netgroup=tuple(), - ), - memberuser=dict( - group=tuple(), - user=tuple(), - ), - memberhost=dict( - hostgroup=tuple(), - host=tuple(), - ), - ), + value=netgroup1, + summary='Modified netgroup "%s"' % netgroup1, result={ - 'dn': fuzzy_netgroupdn, - 'member_netgroup': (netgroup2,), - 'cn': [netgroup1], - 'description': [u'Updated netgroup 1'], - 'nisdomainname': [u'%s' % api.env.domain], - 'externalhost': [unknown_host], + 'memberhost_host': (host1,), + 'memberhost_hostgroup': (hostgroup1,), + 'memberuser_user': (user1,), + 'memberuser_group': (group1,), + 'member_netgroup': (netgroup2,), + 'cn': [netgroup1], + 'description': ['Updated netgroup 1'], + 'nisdomainname': ['%s' % api.env.domain], + 'externalhost': [unknown_host], }, ), ), dict( - desc='Remove netgroup %r from netgroup %r' % (netgroup2, netgroup1), + desc='Modify description using setattr for %r' % netgroup1, command=( - 'netgroup_remove_member', [netgroup1], dict(netgroup=netgroup2) + 'netgroup_mod', [netgroup1], + dict(setattr='description=setattr description') ), expected=dict( - completed=1, - failed=dict( - member=dict( - netgroup=tuple(), - ), - memberuser=dict( - group=tuple(), - user=tuple(), - ), - memberhost=dict( - hostgroup=tuple(), - host=tuple(), - ), - ), + value=netgroup1, + summary='Modified netgroup "%s"' % netgroup1, result={ - 'dn': fuzzy_netgroupdn, - 'cn': [netgroup1], - 'description': [u'Updated netgroup 1'], - 'nisdomainname': [u'%s' % api.env.domain], - 'externalhost': [unknown_host], + 'memberhost_host': (host1,), + 'memberhost_hostgroup': (hostgroup1,), + 'memberuser_user': (user1,), + 'memberuser_group': (group1,), + 'member_netgroup': (netgroup2,), + 'cn': [netgroup1], + 'description': ['setattr description'], + 'nisdomainname': ['%s' % api.env.domain], + 'externalhost': [unknown_host], }, ), ), dict( - desc='Remove host %r from netgroup %r again' % (host1, netgroup1), + desc='Modify nisdomain using setattr for %r' % netgroup1, command=( - 'netgroup_remove_member', [netgroup1], dict(host=host1) + 'netgroup_mod', [netgroup1], + dict(setattr='nisdomainname=setattrnisdom') ), expected=dict( - completed=0, - failed=dict( - member=dict( - netgroup=tuple(), - ), - memberuser=dict( - group=tuple(), - user=tuple(), - ), - memberhost=dict( - hostgroup=tuple(), - host=[('%s' % host1, u'This entry is not a member')] - ), - ), + value=netgroup1, + summary='Modified netgroup "%s"' % netgroup1, result={ - 'dn': fuzzy_netgroupdn, - 'cn': [netgroup1], - 'description': [u'Updated netgroup 1'], - 'nisdomainname': [u'%s' % api.env.domain], - 'externalhost': [unknown_host], + 'memberhost_host': (host1,), + 'memberhost_hostgroup': (hostgroup1,), + 'memberuser_user': (user1,), + 'memberuser_group': (group1,), + 'member_netgroup': (netgroup2,), + 'cn': [netgroup1], + 'description': ['setattr description'], + 'nisdomainname': ['setattrnisdom'], + 'externalhost': [unknown_host], }, ), ), dict( - desc='Remove hostgroup %r from netgroup %r again' % (hostgroup1, netgroup1), + desc='Restore description and nisdomain for %r' % netgroup1, command=( - 'netgroup_remove_member', [netgroup1], dict(hostgroup=hostgroup1) + 'netgroup_mod', [netgroup1], + dict(description='Updated netgroup 1', + nisdomainname='%s' % api.env.domain) ), expected=dict( - completed=0, - failed=dict( - member=dict( - netgroup=tuple(), - ), - memberuser=dict( - group=tuple(), - user=tuple(), - ), - memberhost=dict( - hostgroup=[('%s' % hostgroup1, u'This entry is not a member')], - host=tuple(), - ), - ), + value=netgroup1, + summary='Modified netgroup "%s"' % netgroup1, result={ - 'dn': fuzzy_netgroupdn, - 'cn': [netgroup1], - 'description': [u'Updated netgroup 1'], - 'nisdomainname': [u'%s' % api.env.domain], - 'externalhost': [unknown_host], + 'memberhost_host': (host1,), + 'memberhost_hostgroup': (hostgroup1,), + 'memberuser_user': (user1,), + 'memberuser_group': (group1,), + 'member_netgroup': (netgroup2,), + 'cn': [netgroup1], + 'description': ['Updated netgroup 1'], + 'nisdomainname': ['%s' % api.env.domain], + 'externalhost': [unknown_host], }, ), ), dict( - desc='Remove user %r from netgroup %r again' % (user1, netgroup1), + desc='Set externalhost using setattr for %r' % netgroup1, command=( - 'netgroup_remove_member', [netgroup1], dict(user=user1) + 'netgroup_mod', [netgroup1], + dict(setattr='externalhost=setattr_exthost') ), expected=dict( - completed=0, - failed=dict( - member=dict( - netgroup=tuple(), - ), - memberuser=dict( - group=tuple(), - user=[('%s' % user1, u'This entry is not a member')], - ), - memberhost=dict( - hostgroup=tuple(), - host=tuple(), - ), - ), + value=netgroup1, + summary='Modified netgroup "%s"' % netgroup1, result={ - 'dn': fuzzy_netgroupdn, - 'cn': [netgroup1], - 'description': [u'Updated netgroup 1'], - 'nisdomainname': [u'%s' % api.env.domain], - 'externalhost': [unknown_host], + 'memberhost_host': (host1,), + 'memberhost_hostgroup': (hostgroup1,), + 'memberuser_user': (user1,), + 'memberuser_group': (group1,), + 'member_netgroup': (netgroup2,), + 'cn': [netgroup1], + 'description': ['Updated netgroup 1'], + 'nisdomainname': ['%s' % api.env.domain], + 'externalhost': ['setattr_exthost'], }, ), ), dict( - desc='Remove group %r from netgroup %r again' % (group1, netgroup1), + desc='Add externalhost using addattr for %r' % netgroup1, command=( - 'netgroup_remove_member', [netgroup1], dict(group=group1) + 'netgroup_mod', [netgroup1], + dict(addattr='externalhost=addattr_exthost') ), expected=dict( - completed=0, - failed=dict( - member=dict( - netgroup=tuple(), - ), - memberuser=dict( - group= [('%s' % group1, u'This entry is not a member')], - user=tuple(), - ), - memberhost=dict( - hostgroup=tuple(), - host=tuple(), - ), - ), + value=netgroup1, + summary='Modified netgroup "%s"' % netgroup1, result={ - 'dn': fuzzy_netgroupdn, - 'cn': [netgroup1], - 'description': [u'Updated netgroup 1'], - 'nisdomainname': [u'%s' % api.env.domain], - 'externalhost': [unknown_host], + 'memberhost_host': (host1,), + 'memberhost_hostgroup': (hostgroup1,), + 'memberuser_user': (user1,), + 'memberuser_group': (group1,), + 'member_netgroup': (netgroup2,), + 'cn': [netgroup1], + 'description': ['Updated netgroup 1'], + 'nisdomainname': ['%s' % api.env.domain], + 'externalhost': ['addattr_exthost', 'setattr_exthost'], }, ), ), dict( - desc='Remove netgroup %r from netgroup %r again' % (netgroup2, netgroup1), + desc='Delete one externalhost using delattr for %r' % netgroup1, command=( - 'netgroup_remove_member', [netgroup1], dict(netgroup=netgroup2) + 'netgroup_mod', [netgroup1], + dict(delattr='externalhost=setattr_exthost') ), expected=dict( - completed=0, - failed=dict( - member=dict( - netgroup=[('%s' % netgroup2, u'This entry is not a member')], - ), - memberuser=dict( - group=tuple(), - user=tuple(), - ), - memberhost=dict( - hostgroup=tuple(), - host=tuple(), - ), - ), + value=netgroup1, + summary='Modified netgroup "%s"' % netgroup1, result={ - 'dn': fuzzy_netgroupdn, - 'cn': [netgroup1], - 'description': [u'Updated netgroup 1'], - 'nisdomainname': [u'%s' % api.env.domain], - 'externalhost': [unknown_host], + 'memberhost_host': (host1,), + 'memberhost_hostgroup': (hostgroup1,), + 'memberuser_user': (user1,), + 'memberuser_group': (group1,), + 'member_netgroup': (netgroup2,), + 'cn': [netgroup1], + 'description': ['Updated netgroup 1'], + 'nisdomainname': ['%s' % api.env.domain], + 'externalhost': ['addattr_exthost'], }, ), ), dict( - desc='Delete %r' % netgroup1, - command=('netgroup_del', [netgroup1], {}), + desc='Clear all externalhosts using setattr for %r' % netgroup1, + command=( + 'netgroup_mod', [netgroup1], + dict(setattr='externalhost=') + ), expected=dict( - value=[netgroup1], - summary=u'Deleted netgroup "%s"' % netgroup1, - result=dict(failed=[]), + value=netgroup1, + summary='Modified netgroup "%s"' % netgroup1, + result={ + 'memberhost_host': (host1,), + 'memberhost_hostgroup': (hostgroup1,), + 'memberuser_user': (user1,), + 'memberuser_group': (group1,), + 'member_netgroup': (netgroup2,), + 'cn': [netgroup1], + 'description': ['Updated netgroup 1'], + 'nisdomainname': ['%s' % api.env.domain], + }, ), ), + + dict( + desc='Restore externalhost for %r' % netgroup1, + command=( + 'netgroup_mod', [netgroup1], + dict(addattr='externalhost=%s' % unknown_host) + ), + expected=dict( + value=netgroup1, + summary='Modified netgroup "%s"' % netgroup1, + result={ + 'memberhost_host': (host1,), + 'memberhost_hostgroup': (hostgroup1,), + 'memberuser_user': (user1,), + 'memberuser_group': (group1,), + 'member_netgroup': (netgroup2,), + 'cn': [netgroup1], + 'description': ['Updated netgroup 1'], + 'nisdomainname': ['%s' % api.env.domain], + 'externalhost': [unknown_host], + }, + ), + ), + + + dict( + desc='Modify %r invalid usercat' % netgroup1, + command=( + 'netgroup_mod', [netgroup1], + dict(usercategory='badcat') + ), + expected=errors.ValidationError( + name='usercat', error="must be 'all'"), + ), + + + dict( + desc='Modify %r invalid hostcat' % netgroup1, + command=( + 'netgroup_mod', [netgroup1], + dict(hostcategory='badcat') + ), + expected=errors.ValidationError( + name='hostcat', error="must be 'all'"), + ), + + + dict( + desc='Modify %r with invalid addattr on nisDomainName' % netgroup1, + command=( + 'netgroup_mod', [netgroup1], + dict(addattr='nisdomainname=seconddomain') + ), + expected=errors.OnlyOneValueAllowed(attr='nisdomainname'), + ), + + + dict( + desc='Modify %r with invalid setattr on ipauniqueid' % netgroup1, + command=( + 'netgroup_mod', [netgroup1], + dict(setattr='ipauniqueid=mynew-unique-id') + ), + expected=errors.ValidationError( + name='ipauniqueid', error='attribute is not configurable'), + ), + + + dict( + desc='Modify %r with invalid setattr on dn' % netgroup1, + command=( + 'netgroup_mod', [netgroup1], + dict(setattr='dn=cn=newdn') + ), + expected=errors.ObjectclassViolation( + info='attribute "distinguishedName" not allowed'), + ), + + + dict( + desc='Modify %r with invalid membergroup attribute' % netgroup1, + command=( + 'netgroup_mod', [netgroup1], + dict(setattr='membergroup=%s' % group1) + ), + expected=errors.ObjectclassViolation( + info='attribute "membergroup" not allowed'), + ), + + + dict( + desc='Modify %r with invalid memberhostgroup attr' % netgroup1, + command=( + 'netgroup_mod', [netgroup1], + dict(setattr='memberhostgroup=%s' % hostgroup1) + ), + expected=errors.ObjectclassViolation( + info='attribute "memberhostgroup" not allowed'), + ), + + + dict( + desc='Modify %r with invalid membernetgroup attribute' % netgroup1, + command=( + 'netgroup_mod', [netgroup1], + dict(setattr='membernetgroup=%s' % netgroup2) + ), + expected=errors.ObjectclassViolation( + info='attribute "membernetgroup" not allowed'), + ), + + + dict( + desc='Modify %r with invalid addattr on description' % netgroup1, + command=( + 'netgroup_mod', [netgroup1], + dict(addattr='description=newdesc') + ), + expected=errors.OnlyOneValueAllowed(attr='description'), + ), + + + dict( + desc='Modify %r with invalid nisdomain commas' % netgroup1, + command=( + 'netgroup_mod', [netgroup1], + dict(nisdomainname='test1,test2') + ), + expected=errors.ValidationError( + name='nisdomain', + error='may only include letters, numbers, _, -, and .'), + ), + + + dict( + desc='Modify %r with invalid setattr nisdomain commas' % netgroup1, + command=( + 'netgroup_mod', [netgroup1], + dict(setattr='nisdomainname=test1,test2') + ), + expected=errors.ValidationError( + name='nisdomainname', + error='may only include letters, numbers, _, -, and .'), + ), + + + dict( + desc='Remove host %r from netgroup %r' % (host1, netgroup1), + command=( + 'netgroup_remove_member', [netgroup1], dict(host=host1) + ), + expected=dict( + completed=1, + failed=dict( + member=dict( + netgroup=tuple(), + ), + memberuser=dict( + group=tuple(), + user=tuple(), + ), + memberhost=dict( + hostgroup=tuple(), + host=tuple(), + ), + ), + result={ + 'dn': fuzzy_netgroupdn, + 'memberhost_hostgroup': (hostgroup1,), + 'memberuser_user': (user1,), + 'memberuser_group': (group1,), + 'member_netgroup': (netgroup2,), + 'cn': [netgroup1], + 'description': ['Updated netgroup 1'], + 'nisdomainname': ['%s' % api.env.domain], + 'externalhost': [unknown_host], + }, + ), + ), + + + dict( + desc='Remove hostgroup %r from netgroup %r' % ( + hostgroup1, netgroup1), + command=( + 'netgroup_remove_member', [netgroup1], + dict(hostgroup=hostgroup1) + ), + expected=dict( + completed=1, + failed=dict( + member=dict( + netgroup=tuple(), + ), + memberuser=dict( + group=tuple(), + user=tuple(), + ), + memberhost=dict( + hostgroup=tuple(), + host=tuple(), + ), + ), + result={ + 'dn': fuzzy_netgroupdn, + 'memberuser_user': (user1,), + 'memberuser_group': (group1,), + 'member_netgroup': (netgroup2,), + 'cn': [netgroup1], + 'description': ['Updated netgroup 1'], + 'nisdomainname': ['%s' % api.env.domain], + 'externalhost': [unknown_host], + }, + ), + ), + + + dict( + desc='Remove user %r from netgroup %r' % (user1, netgroup1), + command=( + 'netgroup_remove_member', [netgroup1], dict(user=user1) + ), + expected=dict( + completed=1, + failed=dict( + member=dict( + netgroup=tuple(), + ), + memberuser=dict( + group=tuple(), + user=tuple(), + ), + memberhost=dict( + hostgroup=tuple(), + host=tuple(), + ), + ), + result={ + 'dn': fuzzy_netgroupdn, + 'memberuser_group': (group1,), + 'member_netgroup': (netgroup2,), + 'cn': [netgroup1], + 'description': ['Updated netgroup 1'], + 'nisdomainname': ['%s' % api.env.domain], + 'externalhost': [unknown_host], + }, + ), + ), + + + dict( + desc='Remove group %r from netgroup %r' % (group1, netgroup1), + command=( + 'netgroup_remove_member', [netgroup1], dict(group=group1) + ), + expected=dict( + completed=1, + failed=dict( + member=dict( + netgroup=tuple(), + ), + memberuser=dict( + group=tuple(), + user=tuple(), + ), + memberhost=dict( + hostgroup=tuple(), + host=tuple(), + ), + ), + result={ + 'dn': fuzzy_netgroupdn, + 'member_netgroup': (netgroup2,), + 'cn': [netgroup1], + 'description': ['Updated netgroup 1'], + 'nisdomainname': ['%s' % api.env.domain], + 'externalhost': [unknown_host], + }, + ), + ), + + + dict( + desc='Remove netgroup %r from netgroup %r' % (netgroup2, netgroup1), + command=( + 'netgroup_remove_member', [netgroup1], dict(netgroup=netgroup2) + ), + expected=dict( + completed=1, + failed=dict( + member=dict( + netgroup=tuple(), + ), + memberuser=dict( + group=tuple(), + user=tuple(), + ), + memberhost=dict( + hostgroup=tuple(), + host=tuple(), + ), + ), + result={ + 'dn': fuzzy_netgroupdn, + 'cn': [netgroup1], + 'description': ['Updated netgroup 1'], + 'nisdomainname': ['%s' % api.env.domain], + 'externalhost': [unknown_host], + }, + ), + ), + + + dict( + desc='Remove host %r from netgroup %r again' % (host1, netgroup1), + command=( + 'netgroup_remove_member', [netgroup1], dict(host=host1) + ), + expected=dict( + completed=0, + failed=dict( + member=dict( + netgroup=tuple(), + ), + memberuser=dict( + group=tuple(), + user=tuple(), + ), + memberhost=dict( + hostgroup=tuple(), + host=[('%s' % host1, 'This entry is not a member')] + ), + ), + result={ + 'dn': fuzzy_netgroupdn, + 'cn': [netgroup1], + 'description': ['Updated netgroup 1'], + 'nisdomainname': ['%s' % api.env.domain], + 'externalhost': [unknown_host], + }, + ), + ), + + + dict( + desc='Remove hostgroup %r from netgroup %r again' % ( + hostgroup1, netgroup1), + command=( + 'netgroup_remove_member', [netgroup1], + dict(hostgroup=hostgroup1) + ), + expected=dict( + completed=0, + failed=dict( + member=dict( + netgroup=tuple(), + ), + memberuser=dict( + group=tuple(), + user=tuple(), + ), + memberhost=dict( + hostgroup=[( + '%s' % hostgroup1, + 'This entry is not a member')], + host=tuple(), + ), + ), + result={ + 'dn': fuzzy_netgroupdn, + 'cn': [netgroup1], + 'description': ['Updated netgroup 1'], + 'nisdomainname': ['%s' % api.env.domain], + 'externalhost': [unknown_host], + }, + ), + ), + + + dict( + desc='Remove user %r from netgroup %r again' % (user1, netgroup1), + command=( + 'netgroup_remove_member', [netgroup1], dict(user=user1) + ), + expected=dict( + completed=0, + failed=dict( + member=dict( + netgroup=tuple(), + ), + memberuser=dict( + group=tuple(), + user=[('%s' % user1, 'This entry is not a member')], + ), + memberhost=dict( + hostgroup=tuple(), + host=tuple(), + ), + ), + result={ + 'dn': fuzzy_netgroupdn, + 'cn': [netgroup1], + 'description': ['Updated netgroup 1'], + 'nisdomainname': ['%s' % api.env.domain], + 'externalhost': [unknown_host], + }, + ), + ), + + + dict( + desc='Remove group %r from netgroup %r again' % (group1, netgroup1), + command=( + 'netgroup_remove_member', [netgroup1], dict(group=group1) + ), + expected=dict( + completed=0, + failed=dict( + member=dict( + netgroup=tuple(), + ), + memberuser=dict( + group=[('%s' % group1, 'This entry is not a member')], + user=tuple(), + ), + memberhost=dict( + hostgroup=tuple(), + host=tuple(), + ), + ), + result={ + 'dn': fuzzy_netgroupdn, + 'cn': [netgroup1], + 'description': ['Updated netgroup 1'], + 'nisdomainname': ['%s' % api.env.domain], + 'externalhost': [unknown_host], + }, + ), + ), + + + dict( + desc='Remove netgroup %r from netgroup %r again' % ( + netgroup2, netgroup1), + command=( + 'netgroup_remove_member', [netgroup1], dict(netgroup=netgroup2) + ), + expected=dict( + completed=0, + failed=dict( + member=dict( + netgroup=[( + '%s' % netgroup2, + 'This entry is not a member')], + ), + memberuser=dict( + group=tuple(), + user=tuple(), + ), + memberhost=dict( + hostgroup=tuple(), + host=tuple(), + ), + ), + result={ + 'dn': fuzzy_netgroupdn, + 'cn': [netgroup1], + 'description': ['Updated netgroup 1'], + 'nisdomainname': ['%s' % api.env.domain], + 'externalhost': [unknown_host], + }, + ), + ), + + + dict( + desc='Remove member from non-existent netgroup', + command=( + 'netgroup_remove_member', ['notfoundnetgroup'], + dict(user=user1) + ), + expected=errors.NotFound( + reason='notfoundnetgroup: netgroup not found'), + ), + + + dict( + desc='Create %r with usercat=all' % netgroup_usercat_mod, + command=( + 'netgroup_add', [netgroup_usercat_mod], + dict(description='Test usercat mod', + nisdomainname=custom_nisdomain, usercategory='all') + ), + expected=dict( + value=netgroup_usercat_mod, + summary='Added netgroup "%s"' % netgroup_usercat_mod, + result=dict( + dn=fuzzy_netgroupdn, + cn=[netgroup_usercat_mod], + objectclass=objectclasses.netgroup, + description=['Test usercat mod'], + nisdomainname=[custom_nisdomain], + usercategory=['all'], + ipauniqueid=[fuzzy_uuid], + ), + ), + ), + + dict( + desc='Clear usercat via setattr for %r' % netgroup_usercat_mod, + command=( + 'netgroup_mod', [netgroup_usercat_mod], + dict(setattr='usercategory=') + ), + expected=dict( + value=netgroup_usercat_mod, + summary='Modified netgroup "%s"' % netgroup_usercat_mod, + result={ + 'cn': [netgroup_usercat_mod], + 'description': ['Test usercat mod'], + 'nisdomainname': [custom_nisdomain], + }, + ), + ), + + dict( + desc='Create %r with hostcat=all' % netgroup_hostcat_mod, + command=( + 'netgroup_add', [netgroup_hostcat_mod], + dict(description='Test hostcat mod', + nisdomainname=custom_nisdomain, hostcategory='all') + ), + expected=dict( + value=netgroup_hostcat_mod, + summary='Added netgroup "%s"' % netgroup_hostcat_mod, + result=dict( + dn=fuzzy_netgroupdn, + cn=[netgroup_hostcat_mod], + objectclass=objectclasses.netgroup, + description=['Test hostcat mod'], + nisdomainname=[custom_nisdomain], + hostcategory=['all'], + ipauniqueid=[fuzzy_uuid], + ), + ), + ), + + dict( + desc='Clear hostcat via setattr for %r' % netgroup_hostcat_mod, + command=( + 'netgroup_mod', [netgroup_hostcat_mod], + dict(setattr='hostcategory=') + ), + expected=dict( + value=netgroup_hostcat_mod, + summary='Modified netgroup "%s"' % netgroup_hostcat_mod, + result={ + 'cn': [netgroup_hostcat_mod], + 'description': ['Test hostcat mod'], + 'nisdomainname': [custom_nisdomain], + }, + ), + ), + + + # ===== netgroup-find tests ===== + # Setup: Create test entities for find tests + dict( + desc='Create user %r for find tests' % fnd_user1, + command=( + 'user_add', [fnd_user1], + dict(givenname='Find', sn='User1') + ), + expected=dict( + value=fnd_user1, + summary='Added user "%s"' % fnd_user1, + result=get_user_result(fnd_user1, 'Find', 'User1', 'add'), + ), + ), + + dict( + desc='Create user %r for find tests' % fnd_user2, + command=( + 'user_add', [fnd_user2], + dict(givenname='Find', sn='User2') + ), + expected=dict( + value=fnd_user2, + summary='Added user "%s"' % fnd_user2, + result=get_user_result(fnd_user2, 'Find', 'User2', 'add'), + ), + ), + + dict( + desc='Create group %r for find tests' % fnd_group, + command=( + 'group_add', [fnd_group], + dict(description='test') + ), + expected=dict( + value=fnd_group, + summary='Added group "%s"' % fnd_group, + result=dict( + cn=[fnd_group], + description=['test'], + gidnumber=[fuzzy_digits], + objectclass=fuzzy_set_optional_oc( + objectclasses.posixgroup, 'ipantgroupattrs'), + ipauniqueid=[fuzzy_uuid], + dn=DN( + ('cn', fnd_group), ('cn', 'groups'), + ('cn', 'accounts'), api.env.basedn), + ), + ), + ), + + dict( + desc='Create host %r for find tests' % fnd_host, + command=( + 'host_add', [fnd_host], + dict( + description='Test host for find', + l='Undisclosed location', + force=True, + ) + ), + expected=dict( + value=fnd_host, + summary='Added host "%s"' % fnd_host, + result=dict( + dn=DN( + ('fqdn', fnd_host), ('cn', 'computers'), + ('cn', 'accounts'), api.env.basedn), + fqdn=[fnd_host], + description=['Test host for find'], + l=['Undisclosed location'], + krbprincipalname=[ + 'host/%s@%s' % (fnd_host, api.env.realm)], + krbcanonicalname=[ + 'host/%s@%s' % (fnd_host, api.env.realm)], + objectclass=objectclasses.host, + ipauniqueid=[fuzzy_uuid], + managedby_host=[fnd_host], + has_keytab=False, + has_password=False, + ), + ), + ), + + dict( + desc='Create hostgroup %r for find tests' % fnd_hostgroup, + command=( + 'hostgroup_add', [fnd_hostgroup], + dict(description='test') + ), + expected=dict( + value=fnd_hostgroup, + summary='Added hostgroup "%s"' % fnd_hostgroup, + result=dict( + dn=DN( + ('cn', fnd_hostgroup), ('cn', 'hostgroups'), + ('cn', 'accounts'), api.env.basedn), + cn=[fnd_hostgroup], + objectclass=objectclasses.hostgroup, + description=['test'], + mepmanagedentry=[DN( + ('cn', fnd_hostgroup), ('cn', 'ng'), ('cn', 'alt'), + api.env.basedn)], + ipauniqueid=[fuzzy_uuid], + ), + ), + ), + + # Create netgroups with various attributes for find tests + dict( + desc='Create netgroup %r with nisdomain for find tests' % fnd_ng1, + command=( + 'netgroup_add', [fnd_ng1], + dict(description='findtest', nisdomainname=fnd_nisdomain) + ), + expected=dict( + value=fnd_ng1, + summary='Added netgroup "%s"' % fnd_ng1, + result=dict( + dn=fuzzy_netgroupdn, + cn=[fnd_ng1], + objectclass=objectclasses.netgroup, + description=['findtest'], + nisdomainname=[fnd_nisdomain], + ipauniqueid=[fuzzy_uuid], + ), + ), + ), + + dict( + desc='Create netgroup %r with usercat/hostcat=all' % fnd_ng2, + command=( + 'netgroup_add', [fnd_ng2], + dict(description='findtest2', + usercategory='all', hostcategory='all') + ), + expected=dict( + value=fnd_ng2, + summary='Added netgroup "%s"' % fnd_ng2, + result=dict( + dn=fuzzy_netgroupdn, + cn=[fnd_ng2], + objectclass=objectclasses.netgroup, + description=['findtest2'], + nisdomainname=['%s' % api.env.domain], + usercategory=['all'], + hostcategory=['all'], + ipauniqueid=[fuzzy_uuid], + ), + ), + ), + + dict( + desc='Create netgroup %r for find tests' % fnd_ng3, + command=( + 'netgroup_add', [fnd_ng3], + dict(description='findtest3') + ), + expected=dict( + value=fnd_ng3, + summary='Added netgroup "%s"' % fnd_ng3, + result=dict( + dn=fuzzy_netgroupdn, + cn=[fnd_ng3], + objectclass=objectclasses.netgroup, + description=['findtest3'], + nisdomainname=['%s' % api.env.domain], + ipauniqueid=[fuzzy_uuid], + ), + ), + ), + + # Add members to fnd_ng1 + dict( + desc='Add user %r to netgroup %r' % (fnd_user1, fnd_ng1), + command=( + 'netgroup_add_member', [fnd_ng1], + dict(user=fnd_user1) + ), + expected=dict( + completed=1, + failed=dict( + member=dict(netgroup=tuple()), + memberuser=dict(group=tuple(), user=tuple()), + memberhost=dict(hostgroup=tuple(), host=tuple()), + ), + result={ + 'dn': fuzzy_netgroupdn, + 'memberuser_user': (fnd_user1,), + 'cn': [fnd_ng1], + 'description': ['findtest'], + 'nisdomainname': [fnd_nisdomain], + }, + ), + ), + + dict( + desc='Add group %r to netgroup %r' % (fnd_group, fnd_ng1), + command=( + 'netgroup_add_member', [fnd_ng1], + dict(group=fnd_group) + ), + expected=dict( + completed=1, + failed=dict( + member=dict(netgroup=tuple()), + memberuser=dict(group=tuple(), user=tuple()), + memberhost=dict(hostgroup=tuple(), host=tuple()), + ), + result={ + 'dn': fuzzy_netgroupdn, + 'memberuser_user': (fnd_user1,), + 'memberuser_group': (fnd_group,), + 'cn': [fnd_ng1], + 'description': ['findtest'], + 'nisdomainname': [fnd_nisdomain], + }, + ), + ), + + dict( + desc='Add host %r to netgroup %r' % (fnd_host, fnd_ng1), + command=( + 'netgroup_add_member', [fnd_ng1], + dict(host=fnd_host) + ), + expected=dict( + completed=1, + failed=dict( + member=dict(netgroup=tuple()), + memberuser=dict(group=tuple(), user=tuple()), + memberhost=dict(hostgroup=tuple(), host=tuple()), + ), + result={ + 'dn': fuzzy_netgroupdn, + 'memberuser_user': (fnd_user1,), + 'memberuser_group': (fnd_group,), + 'memberhost_host': (fnd_host,), + 'cn': [fnd_ng1], + 'description': ['findtest'], + 'nisdomainname': [fnd_nisdomain], + }, + ), + ), + + dict( + desc='Add hostgroup %r to netgroup %r' % (fnd_hostgroup, fnd_ng1), + command=( + 'netgroup_add_member', [fnd_ng1], + dict(hostgroup=fnd_hostgroup) + ), + expected=dict( + completed=1, + failed=dict( + member=dict(netgroup=tuple()), + memberuser=dict(group=tuple(), user=tuple()), + memberhost=dict(hostgroup=tuple(), host=tuple()), + ), + result={ + 'dn': fuzzy_netgroupdn, + 'memberuser_user': (fnd_user1,), + 'memberuser_group': (fnd_group,), + 'memberhost_host': (fnd_host,), + 'memberhost_hostgroup': (fnd_hostgroup,), + 'cn': [fnd_ng1], + 'description': ['findtest'], + 'nisdomainname': [fnd_nisdomain], + }, + ), + ), + + # Add fnd_ng1 as member of fnd_ng3 (nested netgroup) + dict( + desc='Add netgroup %r to netgroup %r' % (fnd_ng1, fnd_ng3), + command=( + 'netgroup_add_member', [fnd_ng3], + dict(netgroup=fnd_ng1) + ), + expected=dict( + completed=1, + failed=dict( + member=dict(netgroup=tuple()), + memberuser=dict(group=tuple(), user=tuple()), + memberhost=dict(hostgroup=tuple(), host=tuple()), + ), + result={ + 'dn': fuzzy_netgroupdn, + 'member_netgroup': (fnd_ng1,), + 'cn': [fnd_ng3], + 'description': ['findtest3'], + 'nisdomainname': ['%s' % api.env.domain], + }, + ), + ), + + # Find tests - positive scenarios + dict( + desc='Find netgroup by exact name %r' % fnd_ng1, + command=('netgroup_find', [], dict(cn=fnd_ng1)), + expected=dict( + count=1, + truncated=False, + summary='1 netgroup matched', + result=[ + { + 'dn': fuzzy_netgroupdn, + 'cn': [fnd_ng1], + 'description': ['findtest'], + 'nisdomainname': [fnd_nisdomain], + }, + ], + ), + ), + + dict( + desc='Find netgroup by description findtest', + command=('netgroup_find', [], dict(description='findtest')), + expected=dict( + count=1, + truncated=False, + summary='1 netgroup matched', + result=[ + { + 'dn': fuzzy_netgroupdn, + 'cn': [fnd_ng1], + 'description': ['findtest'], + 'nisdomainname': [fnd_nisdomain], + }, + ], + ), + ), + + dict( + desc='Find netgroup by nisdomain %r' % fnd_nisdomain, + command=('netgroup_find', [], dict(nisdomainname=fnd_nisdomain)), + expected=dict( + count=1, + truncated=False, + summary='1 netgroup matched', + result=[ + { + 'dn': fuzzy_netgroupdn, + 'cn': [fnd_ng1], + 'description': ['findtest'], + 'nisdomainname': [fnd_nisdomain], + }, + ], + ), + ), + + dict( + desc='Find netgroup by usercat=all', + command=('netgroup_find', [], dict(usercategory='all')), + expected=dict( + count=1, + truncated=False, + summary='1 netgroup matched', + result=[ + { + 'dn': fuzzy_netgroupdn, + 'cn': [fnd_ng2], + 'description': ['findtest2'], + 'nisdomainname': ['%s' % api.env.domain], + 'usercategory': ['all'], + 'hostcategory': ['all'], + }, + ], + ), + ), + + dict( + desc='Find netgroup by hostcat=all', + command=('netgroup_find', [], dict(hostcategory='all')), + expected=dict( + count=1, + truncated=False, + summary='1 netgroup matched', + result=[ + { + 'dn': fuzzy_netgroupdn, + 'cn': [fnd_ng2], + 'description': ['findtest2'], + 'nisdomainname': ['%s' % api.env.domain], + 'usercategory': ['all'], + 'hostcategory': ['all'], + }, + ], + ), + ), + + dict( + desc='Find netgroup by user %r' % fnd_user1, + command=('netgroup_find', [], dict(user=fnd_user1)), + expected=dict( + count=1, + truncated=False, + summary='1 netgroup matched', + result=[ + { + 'dn': fuzzy_netgroupdn, + 'cn': [fnd_ng1], + 'description': ['findtest'], + 'nisdomainname': [fnd_nisdomain], + }, + ], + ), + ), + + dict( + desc='Find netgroup by group %r' % fnd_group, + command=('netgroup_find', [], dict(group=fnd_group)), + expected=dict( + count=1, + truncated=False, + summary='1 netgroup matched', + result=[ + { + 'dn': fuzzy_netgroupdn, + 'cn': [fnd_ng1], + 'description': ['findtest'], + 'nisdomainname': [fnd_nisdomain], + }, + ], + ), + ), + + dict( + desc='Find netgroup by host %r' % fnd_host, + command=('netgroup_find', [], dict(host=fnd_host)), + expected=dict( + count=1, + truncated=False, + summary='1 netgroup matched', + result=[ + { + 'dn': fuzzy_netgroupdn, + 'cn': [fnd_ng1], + 'description': ['findtest'], + 'nisdomainname': [fnd_nisdomain], + }, + ], + ), + ), + + dict( + desc='Find netgroup by hostgroup %r' % fnd_hostgroup, + command=('netgroup_find', [], dict(hostgroup=fnd_hostgroup)), + expected=dict( + count=1, + truncated=False, + summary='1 netgroup matched', + result=[ + { + 'dn': fuzzy_netgroupdn, + 'cn': [fnd_ng1], + 'description': ['findtest'], + 'nisdomainname': [fnd_nisdomain], + }, + ], + ), + ), + + dict( + desc='Find netgroup by member netgroup %r' % fnd_ng1, + command=('netgroup_find', [], dict(netgroup=fnd_ng1)), + expected=dict( + count=1, + truncated=False, + summary='1 netgroup matched', + result=[ + { + 'dn': fuzzy_netgroupdn, + 'cn': [fnd_ng3], + 'description': ['findtest3'], + 'nisdomainname': ['%s' % api.env.domain], + }, + ], + ), + ), + + dict( + desc='Find netgroup by in_netgroup %r' % fnd_ng3, + command=('netgroup_find', [], dict(in_netgroup=fnd_ng3)), + expected=dict( + count=1, + truncated=False, + summary='1 netgroup matched', + result=[ + { + 'dn': fuzzy_netgroupdn, + 'cn': [fnd_ng1], + 'description': ['findtest'], + 'nisdomainname': [fnd_nisdomain], + }, + ], + ), + ), + + # Find tests - negative scenarios (0 matches) + dict( + desc='Find netgroup with nonexistent name returns 0', + command=('netgroup_find', ['nonexistent_fnd'], {}), + expected=dict( + count=0, + truncated=False, + summary='0 netgroups matched', + result=[], + ), + ), + + dict( + desc='Find netgroup with bad user returns 0', + command=('netgroup_find', [], dict(user='baduser_fnd')), + expected=dict( + count=0, + truncated=False, + summary='0 netgroups matched', + result=[], + ), + ), + + dict( + desc='Find netgroup with bad group returns 0', + command=('netgroup_find', [], dict(group='badgroup_fnd')), + expected=dict( + count=0, + truncated=False, + summary='0 netgroups matched', + result=[], + ), + ), + + dict( + desc='Find netgroup with bad host returns 0', + command=('netgroup_find', [], dict(host='badhost_fnd')), + expected=dict( + count=0, + truncated=False, + summary='0 netgroups matched', + result=[], + ), + ), + + dict( + desc='Find netgroup with bad hostgroup returns 0', + command=('netgroup_find', [], dict(hostgroup='badhg_fnd')), + expected=dict( + count=0, + truncated=False, + summary='0 netgroups matched', + result=[], + ), + ), + + dict( + desc='Find netgroup with bad netgroup returns 0', + command=('netgroup_find', [], dict(netgroup='badng_fnd')), + expected=dict( + count=0, + truncated=False, + summary='0 netgroups matched', + result=[], + ), + ), + + # Invalid parameter type tests + dict( + desc='Find netgroup with invalid timelimit type', + command=('netgroup_find', [], dict(timelimit='bad')), + expected=errors.ConversionError( + name='timelimit', + error='must be an integer'), + ), + + dict( + desc='Find netgroup with invalid sizelimit type', + command=('netgroup_find', [], dict(sizelimit='bad')), + expected=errors.ConversionError( + name='sizelimit', + error='must be an integer'), + ), + + # Space input tests (bz798792) + dict( + desc='Find netgroup with space in netgroup param (bz798792)', + command=('netgroup_find', [], dict(netgroup=' ')), + expected=dict( + count=0, + truncated=False, + summary='0 netgroups matched', + result=[], + ), + ), + + dict( + desc='Find netgroup with space in user param (bz798792)', + command=('netgroup_find', [], dict(user=' ')), + expected=dict( + count=0, + truncated=False, + summary='0 netgroups matched', + result=[], + ), + ), + + dict( + desc='Find netgroup with space in group param (bz798792)', + command=('netgroup_find', [], dict(group=' ')), + expected=dict( + count=0, + truncated=False, + summary='0 netgroups matched', + result=[], + ), + ), + + dict( + desc='Find netgroup with space in host param (bz798792)', + command=('netgroup_find', [], dict(host=' ')), + expected=dict( + count=0, + truncated=False, + summary='0 netgroups matched', + result=[], + ), + ), + + dict( + desc='Find netgroup with space in hostgroup param (bz798792)', + command=('netgroup_find', [], dict(hostgroup=' ')), + expected=dict( + count=0, + truncated=False, + summary='0 netgroups matched', + result=[], + ), + ), + + dict( + desc='Find netgroup with space in in_netgroup param (bz798792)', + command=('netgroup_find', [], dict(in_netgroup=' ')), + expected=dict( + count=0, + truncated=False, + summary='0 netgroups matched', + result=[], + ), + ), ] # No way to convert this test just yet. -- 2.53.0