Import Upstream version 4.12.4
This commit is contained in:
@@ -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)
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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}
|
||||
|
||||
145
ipatests/test_ipapython/test_ldap_cache.py
Normal file
145
ipatests/test_ipapython/test_ldap_cache.py
Normal 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)
|
||||
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user