Import Upstream version 4.12.4

This commit is contained in:
geos_one
2025-08-12 22:28:56 +02:00
parent 03a8170b15
commit 9181ee2487
1629 changed files with 874094 additions and 554378 deletions

View File

@@ -76,8 +76,8 @@ def test_dbm_raise():
with pytest.raises(ValueError) as e:
NSSDatabase(dbtype="dbm")
assert (
str(e.value) == "NSS is built without support of the legacy "
"database(DBM)"
"NSS is built without support of the legacy database(DBM)"
in str(e.value)
)

View File

@@ -19,9 +19,8 @@
import datetime
import email.utils
import calendar
from ipapython.cookie import Cookie
from ipapython.ipautil import datetime_from_utctimestamp
import pytest
pytestmark = pytest.mark.tier0
@@ -148,17 +147,21 @@ class TestExpires:
@pytest.fixture(autouse=True)
def expires_setup(self):
# Force microseconds to zero because cookie timestamps only have second resolution
self.now = datetime.datetime.utcnow().replace(microsecond=0)
self.now_timestamp = calendar.timegm(self.now.utctimetuple())
self.now = datetime.datetime.now(
tz=datetime.timezone.utc).replace(microsecond=0)
self.now_timestamp = datetime_from_utctimestamp(
self.now.utctimetuple(), units=1).timestamp()
self.now_string = email.utils.formatdate(self.now_timestamp, usegmt=True)
self.max_age = 3600 # 1 hour
self.age_expiration = self.now + datetime.timedelta(seconds=self.max_age)
self.age_timestamp = calendar.timegm(self.age_expiration.utctimetuple())
self.age_timestamp = datetime_from_utctimestamp(
self.age_expiration.utctimetuple(), units=1).timestamp()
self.age_string = email.utils.formatdate(self.age_timestamp, usegmt=True)
self.expires = self.now + datetime.timedelta(days=1) # 1 day
self.expires_timestamp = calendar.timegm(self.expires.utctimetuple())
self.expires_timestamp = datetime_from_utctimestamp(
self.expires.utctimetuple(), units=1).timestamp()
self.expires_string = email.utils.formatdate(self.expires_timestamp, usegmt=True)
def test_expires(self):
@@ -327,7 +330,8 @@ class TestAttributes:
assert cookie.max_age is None
cookie.expires = 'Sun, 06 Nov 1994 08:49:37 GMT'
assert cookie.expires == datetime.datetime(1994, 11, 6, 8, 49, 37)
assert cookie.expires == datetime.datetime(
1994, 11, 6, 8, 49, 37, tzinfo=datetime.timezone.utc)
cookie.expires = None
assert cookie.expires is None
@@ -398,7 +402,9 @@ class TestHTTPReturn:
assert cookie.http_return_ok(self.url)
def test_expires(self):
now = datetime.datetime.utcnow().replace(microsecond=0)
now = datetime.datetime.now(
tz=datetime.timezone.utc).replace(
microsecond=0)
# expires 1 day from now
expires = now + datetime.timedelta(days=1)
@@ -433,17 +439,21 @@ class TestNormalization:
@pytest.fixture(autouse=True)
def normalization_setup(self):
# Force microseconds to zero because cookie timestamps only have second resolution
self.now = datetime.datetime.utcnow().replace(microsecond=0)
self.now_timestamp = calendar.timegm(self.now.utctimetuple())
self.now = datetime.datetime.now(
tz=datetime.timezone.utc).replace(microsecond=0)
self.now_timestamp = datetime_from_utctimestamp(
self.now.utctimetuple(), units=1).timestamp()
self.now_string = email.utils.formatdate(self.now_timestamp, usegmt=True)
self.max_age = 3600 # 1 hour
self.age_expiration = self.now + datetime.timedelta(seconds=self.max_age)
self.age_timestamp = calendar.timegm(self.age_expiration.utctimetuple())
self.age_timestamp = datetime_from_utctimestamp(
self.age_expiration.utctimetuple(), units=1).timestamp()
self.age_string = email.utils.formatdate(self.age_timestamp, usegmt=True)
self.expires = self.now + datetime.timedelta(days=1) # 1 day
self.expires_timestamp = calendar.timegm(self.expires.utctimetuple())
self.expires_timestamp = datetime_from_utctimestamp(
self.expires.utctimetuple(), units=1).timestamp()
self.expires_string = email.utils.formatdate(self.expires_timestamp, usegmt=True)
def test_path_normalization(self):

View File

@@ -18,6 +18,10 @@ WHITESPACE_CONFIG = [
'foobar\t2\n',
]
SUBSTRING_CONFIG = [
'foobar=2\n',
]
class test_set_directive_lines:
def test_remove_directive(self):
@@ -88,6 +92,7 @@ class test_set_directive:
class test_get_directive:
def test_get_directive(self, tmpdir):
"""Test retrieving known values from a config file"""
configfile = tmpdir.join('config')
configfile.write(''.join(EXAMPLE_CONFIG))
@@ -97,6 +102,34 @@ class test_get_directive:
assert '2' == directivesetter.get_directive(str(configfile),
'foobar',
separator='=')
assert None is directivesetter.get_directive(str(configfile),
'notfound',
separator='=')
def test_get_directive_substring(self, tmpdir):
"""Test retrieving values from a config file where there is
a similar substring that is not present.
"""
configfile = tmpdir.join('config')
configfile.write(''.join(SUBSTRING_CONFIG))
assert None is directivesetter.get_directive(str(configfile),
'foo',
separator='=')
assert '2' == directivesetter.get_directive(str(configfile),
'foobar',
separator='=')
def test_get_directive_none(self, tmpdir):
"""Test retrieving a value from a config file where the
directive is None. i.e. don't fail.
"""
configfile = tmpdir.join('config')
configfile.write(''.join(EXAMPLE_CONFIG))
assert None is directivesetter.get_directive(str(configfile),
None,
separator='=')
class test_get_directive_whitespace:

View File

@@ -531,7 +531,6 @@ class TestRDN:
def test_assignments(self):
rdn = RDN((self.attr1, self.value1))
with pytest.raises(TypeError):
# pylint: disable=unsupported-assignment-operation
rdn[0] = self.ava2
def test_iter(self):
@@ -997,10 +996,8 @@ class TestDN:
def test_assignments(self):
dn = DN('t=0,t=1,t=2,t=3,t=4,t=5,t=6,t=7,t=8,t=9')
with pytest.raises(TypeError):
# pylint: disable=unsupported-assignment-operation
dn[0] = RDN('t=a')
with pytest.raises(TypeError):
# pylint: disable=unsupported-assignment-operation
dn[0:1] = [RDN('t=a'), RDN('t=b')]
def test_iter(self):

View File

@@ -55,9 +55,6 @@ class TestSortSRV:
h380 = mksrv(4, 0, 80, u"host3")
assert dnsutil.sort_prio_weight([h1, h3, h380]) == [h1, h3, h380]
hs = mksrv(-1, 0, 443, u"special")
assert dnsutil.sort_prio_weight([h1, h2, hs]) == [hs, h1, h2]
def assert_permutations(self, answers, permutations):
seen = set()
for _unused in range(1000):
@@ -104,3 +101,48 @@ class TestSortURI:
assert dnsutil.sort_prio_weight([h3, h2, h1]) == [h1, h2, h3]
assert dnsutil.sort_prio_weight([h3, h3, h3]) == [h3]
assert dnsutil.sort_prio_weight([h2, h2, h1, h1]) == [h1, h2]
class TestDNSResolver:
@pytest.fixture(name="res")
def resolver(self):
"""Resolver that doesn't read /etc/resolv.conf
/etc/resolv.conf is not mandatory on systems
"""
return dnsutil.DNSResolver(configure=False)
def test_nameservers(self, res):
res.nameservers = ["4.4.4.4", "8.8.8.8"]
assert res.nameservers == ["4.4.4.4", "8.8.8.8"]
def test_nameservers_with_ports(self, res):
res.nameservers = ["4.4.4.4 port 53", "8.8.8.8 port 8053"]
assert res.nameservers == ["4.4.4.4", "8.8.8.8"]
assert res.nameserver_ports == {"4.4.4.4": 53, "8.8.8.8": 8053}
res.nameservers = ["4.4.4.4 port 53", "8.8.8.8 port 8053"]
assert res.nameservers == ["4.4.4.4", "8.8.8.8"]
assert res.nameserver_ports == {"4.4.4.4": 53, "8.8.8.8": 8053}
def test_nameservers_with_bad_ports(self, res):
try:
res.nameservers = ["4.4.4.4 port a"]
except ValueError:
pass
else:
pytest.fail("No fail on bad port a")
try:
res.nameservers = ["4.4.4.4 port -1"]
except ValueError:
pass
else:
pytest.fail("No fail on bad port -1")
try:
res.nameservers = ["4.4.4.4 port 65536"]
except ValueError:
pass
else:
pytest.fail("No fail on bad port 65536")

View File

@@ -24,11 +24,11 @@ Test the `ipapython/ipautil.py` module.
from __future__ import absolute_import
import os
import pwd
import socket
import sys
import tempfile
import textwrap
import time
import pytest
import six
@@ -530,14 +530,13 @@ def test_run_runas():
The test is using 'ipaapi' user as it is configured when
ipa-server-common package is installed.
"""
user = pwd.getpwnam(IPAAPI_USER)
res = ipautil.run(['/usr/bin/id', '-u'], runas=IPAAPI_USER)
assert res.returncode == 0
assert res.raw_output == b'%d\n' % user.pw_uid
assert res.raw_output == b'%d\n' % IPAAPI_USER.uid
res = ipautil.run(['/usr/bin/id', '-g'], runas=IPAAPI_USER)
assert res.returncode == 0
assert res.raw_output == b'%d\n' % user.pw_gid
assert res.raw_output == b'%d\n' % IPAAPI_USER.pgid
@pytest.fixture(scope='function')
@@ -606,3 +605,36 @@ def test_config_replace_variables(tempdir):
with open(conffile, 'r') as f:
newconf = f.read()
assert newconf == expected
def test_sleeper():
start = time.monotonic()
sleep = ipautil.Sleeper(sleep=0.020, timeout=0.200, raises=TimeoutError)
assert sleep
with pytest.raises(TimeoutError):
while True:
sleep()
dur = time.monotonic() - start
assert not sleep
assert dur >= 0.2
# should finish in 0.2, accept longer time in case the system is busy
assert dur < 1.
start = time.monotonic()
loops = 0
sleep = ipautil.Sleeper(sleep=0.020, timeout=0.200)
assert sleep
while True:
if not sleep():
break
loops += 1
dur = time.monotonic() - start
assert not sleep
assert dur >= 0.2
assert dur < 1.
# should be 10 loops, accept 9 for slow systems
assert loops in {9, 10}

View File

@@ -0,0 +1,145 @@
#
# Copyright (C) 2021 FreeIPA Contributors see COPYING for license
#
"""
Test the LDAPCache class.
"""
# pylint: disable=no-member
from ipalib import api, errors
from ipapython import ipaldap
from ipapython.dn import DN
import pytest
def hits_and_misses(cache, hits, misses):
assert cache._cache_hits == hits
assert cache._cache_misses == misses
@pytest.fixture(scope='class')
@pytest.mark.tier1
@pytest.mark.needs_ipaapi
def class_cache(request):
cache = ipaldap.LDAPCache(api.env.ldap_uri)
hits_and_misses(cache, 0, 0)
request.cls.cache = cache
request.cls.userdn = DN(
'uid=testuser', api.env.container_user, api.env.basedn
)
rpcclient = api.Backend.rpcclient
was_connected = rpcclient.isconnected()
if not was_connected:
rpcclient.connect()
api.Command.user_add('testuser', givenname=u'Test', sn=u'User')
yield
try:
api.Command.user_del('testuser')
except Exception:
pass
try:
if not was_connected:
rpcclient.disconnect()
except Exception:
pass
@pytest.mark.usefixtures('class_cache')
@pytest.mark.skip_ipaclient_unittest
@pytest.mark.needs_ipaapi
class TestLDAPCache:
def test_one(self):
dn = DN('uid=notfound', api.env.container_user, api.env.basedn)
try:
self.cache.get_entry(dn)
except errors.EmptyResult:
pass
assert dn in self.cache.cache
exc = self.cache.cache[dn].exception
assert isinstance(exc, errors.EmptyResult)
hits_and_misses(self.cache, 0, 1)
def test_retrieve_exception(self):
dn = DN('uid=notfound', api.env.container_user, api.env.basedn)
try:
self.cache.get_entry(dn)
except errors.EmptyResult:
pass
assert dn in self.cache.cache
exc = self.cache.cache[dn].exception
assert isinstance(exc, errors.EmptyResult)
hits_and_misses(self.cache, 1, 1)
def test_get_testuser(self):
assert self.userdn not in self.cache.cache
self.cache.get_entry(self.userdn)
assert self.userdn in self.cache.cache
hits_and_misses(self.cache, 1, 2)
def test_get_testuser_again(self):
assert self.userdn in self.cache.cache
# get the user again with with no attributes requested (so all)
self.cache.get_entry(self.userdn)
hits_and_misses(self.cache, 2, 2)
# Now get the user with a subset of cached attributes
entry = self.cache.get_entry(self.userdn, ('givenname', 'sn', 'cn'))
# Make sure we only got three attributes, as requested
assert len(entry.items()) == 3
hits_and_misses(self.cache, 3, 2)
def test_update_testuser(self):
entry = self.cache.cache[self.userdn].entry
try:
self.cache.update_entry(entry)
except errors.EmptyModlist:
pass
assert self.userdn not in self.cache.cache
hits_and_misses(self.cache, 3, 2)
def test_modify_testuser(self):
self.cache.get_entry(self.userdn)
entry = self.cache.cache[self.userdn].entry
try:
self.cache.modify_s(entry.dn, [])
except errors.EmptyModlist:
pass
assert self.userdn not in self.cache.cache
hits_and_misses(self.cache, 3, 3)
def test_delete_entry(self):
# We don't care if this is successful or not, just that the
# cache doesn't retain the deleted entry
try:
self.cache.delete_entry(self.userdn)
except Exception:
pass
assert self.userdn not in self.cache.cache
hits_and_misses(self.cache, 3, 3)
def test_add_entry(self):
# We don't care if this is successful or not, just that the
# cache doesn't get the added entry
try:
self.cache.add_entry(self.userdn)
except Exception:
pass
assert self.userdn not in self.cache.cache
hits_and_misses(self.cache, 3, 3)
def test_clear_cache(self):
self.cache.clear_cache()
hits_and_misses(self.cache, 0, 0)

View File

@@ -69,6 +69,10 @@ openssh = 'ssh-rsa %s' % b64
u'%s this is a comment' % openssh),
(u'opt3,opt2="\tx ",opt1,opt2="\\"x " %s comment ' % openssh,
u'opt1,opt2="\\"x ",opt3 %s comment' % openssh),
(u'permitopen=\"1.1.1.1:111\",permitopen=\"2.2.2.2:222\" %s' % openssh,
u'permitopen=\"1.1.1.1:111\",permitopen=\"2.2.2.2:222\" %s' % openssh),
(u'permitlisten=\"1.1.1.1:111\",permitlisten=\"2.2.2.2:222\" %s' % openssh,
u'permitlisten=\"1.1.1.1:111\",permitlisten=\"2.2.2.2:222\" %s' % openssh),
(u'ssh-rsa\n%s' % b64, ValueError),
(u'ssh-rsa\t%s' % b64, ValueError),
(u'vanitas %s' % b64, ValueError),