The commit https://github.com/freeipa/freeipa/commit/a1e76fa0b18ac0f7648c122645f76c3bd4c66818 introduced a regression in the test test_pwpolicy.py::TestPWquality::test_graceperiod_not_replicated.
test_pwpolicy.py::TestPWquality::test_graceperiod_not_replicated
Logs in https://$ARTIFACTS_SERVER/idm-ci/freeipa_upstream_nightly/Nightly-rawhide/master/2026-02-16_10-11/rawhide/test_pwpolicy/2/report.html?sort=result
self = <ipatests.test_integration.test_pwpolicy.TestPWquality object at 0x7f58831f9c70> def test_graceperiod_not_replicated(self): """Test that the grace period is reset on password reset""" dn = "uid={user},cn=users,cn=accounts,{base_dn}".format( user=USER, base_dn=str(self.master.domain.basedn)) # Resetting the password will mark it as expired self.reset_password(self.master) # Generate some logins but don't exceed the limit for _i in range(2, -1, -1): result = self.master.run_command( ["ldapsearch", "-e", "ppolicy", "-D", dn, "-w", PASSWORD, "-b", dn], raiseonerr=False ) # Verify that passwordgraceusertime is not replicated result = tasks.ldapsearch_dm( self.master, dn, ['passwordgraceusertime',], ) assert 'passwordgraceusertime: 3' in result.stdout_text.lower() > result = tasks.ldapsearch_dm( self.replicas[0], dn, ['passwordgraceusertime',], ) _i = 0 dn = 'uid=tuser,cn=users,cn=accounts,dc=ufreeipa,dc=test' result = <pytest_multihost.transport.SSHCommand object at 0x7f5883523770> self = <ipatests.test_integration.test_pwpolicy.TestPWquality object at 0x7f58831f9c70> test_integration/test_pwpolicy.py:478: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ pytest_ipa/integration/tasks.py:2495: in ldapsearch_dm return host.run_command(args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ args = ['ldapsearch', '-x', '-ZZ', '-H', 'ldap://replica.ufreeipa.test', '-D', ...] base = 'uid=tuser,cn=users,cn=accounts,dc=ufreeipa,dc=test' host = <ipatests.pytest_ipa.integration.host.Host replica.ufreeipa.test (replica)> kwargs = {} ldap_args = ['passwordgraceusertime'] scope = 'sub' _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = <ipatests.pytest_ipa.integration.host.Host replica.ufreeipa.test (replica)> argv = ['ldapsearch', '-x', '-ZZ', '-H', 'ldap://replica.ufreeipa.test', '-D', ...] set_env = True, stdin_text = None, log_stdout = True, raiseonerr = True cwd = None, bg = False, encoding = 'utf-8', ok_returncode = 0 def run_command(self, argv, set_env=True, stdin_text=None, log_stdout=True, raiseonerr=True, cwd=None, bg=False, encoding='utf-8', ok_returncode=0): """Wrapper around run_command to log stderr on raiseonerr=True :param ok_returncode: return code considered to be correct, you can pass an integer or sequence of integers """ result = super().run_command( argv, set_env=set_env, stdin_text=stdin_text, log_stdout=log_stdout, raiseonerr=False, cwd=cwd, bg=bg, encoding=encoding ) # in FIPS mode SSH may print noise to stderr, remove the string # "FIPS mode initialized" + optional newline. result.stderr_bytes = FIPS_NOISE_RE.sub(b'', result.stderr_bytes) try: result_ok = result.returncode in ok_returncode except TypeError: result_ok = result.returncode == ok_returncode if not result_ok and raiseonerr: result.log.error('stderr: %s', result.stderr_text) > raise subprocess.CalledProcessError( result.returncode, argv, result.stdout_text, result.stderr_text ) E subprocess.CalledProcessError: Command '['ldapsearch', '-x', '-ZZ', '-H', 'ldap://replica.ufreeipa.test', '-D', 'cn=Directory Manager', '-w', 'Secret.123', '-s', 'sub', '-b', 'uid=tuser,cn=users,cn=accounts,dc=ufreeipa,dc=test', '-o', 'ldif-wrap=no', '-LLL', 'passwordgraceusertime']' returned non-zero exit status 1. __class__ = <class 'ipatests.pytest_ipa.integration.host.Host'> argv = ['ldapsearch', '-x', '-ZZ', '-H', 'ldap://replica.ufreeipa.test', '-D', ...] bg = False cwd = None encoding = 'utf-8' log_stdout = True ok_returncode = 0 raiseonerr = True result = <pytest_multihost.transport.SSHCommand object at 0x7f5883523930> result_ok = False self = <ipatests.pytest_ipa.integration.host.Host replica.ufreeipa.test (replica)> set_env = True stdin_text = None pytest_ipa/integration/host.py:202: CalledProcessError ----------------------------- Captured stderr call ----------------------------- ipa: ERROR: stderr: ldap_start_tls: Can't contact LDAP server (-1)
test_integration/test_pwpolicy.py::TestPWquality::test_graceperiod_not_replicated
The test does not install the replica any more but tries to read data from it.
The test should install the replica.
freeipa-server-4.14.0.dev202602160814+gita1e76fa0b-0.fc45.x86_64
The commit creates a new test class TestPWquality that inherits from BasePWpolicy. As BasePWpolicy overrides the install method with task.install_master instead of super(TestPWPolicy, cls).install(mh), only the master gets installed.
TestPWquality
BasePWpolicy
install
task.install_master
super(TestPWPolicy, cls).install(mh)
The diff can be seen here.
IMO the base class BasePWpolicy should define num_replicas=0 and topology=line, and keep on calling super(TestPWPolicy, cls).install(mh). This way, if a child class overrides num_replicas, the child class will have master + replicas installed without the need to override install.
Metadata Update from @frenaud: - Custom field on_review adjusted to https://github.com/freeipa/freeipa/pull/8186 - Issue assigned to frenaud
master:
ipa-4-12:
ipa-4-13:
Metadata Update from @frenaud: - Issue close_status updated to: fixed - Issue status updated to: Closed (was: Open)