Imported Upstream version 4.6.2

This commit is contained in:
Mario Fetka
2021-07-25 07:32:41 +02:00
commit 8ff3be4216
1788 changed files with 1900965 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
# Authors:
# Jason Gerard DeRose <jderose@redhat.com>
#
# Copyright (C) 2008 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Sub-package containing unit tests for `ipalib` package.
"""

View File

@@ -0,0 +1,47 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR Red Hat
# This file is distributed under the same license as the ipa package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: ipa\n"
"Report-Msgid-Bugs-To: https://fedorahosted.org/freeipa/newticket\n"
"POT-Creation-Date: 2016-08-29 10:39+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
#: ipaclient/frontend.py:28 ipaclient/frontend.py:85
#: ipaserver/plugins/baseldap.py:52
msgid "Failed members"
msgstr ""
#: ipaclient/frontend.py:32 ipaserver/plugins/baseldap.py:169
msgid "Failed source hosts/hostgroups"
msgstr ""
#: ipaclient/frontend.py:36 ipaserver/plugins/baseldap.py:172
msgid "Failed hosts/hostgroups"
msgstr ""
#: ipaclient/frontend.py:40 ipaserver/plugins/baseldap.py:175
msgid "Failed users/groups"
msgstr ""
#: ipaclient/plugins/dns.py:249
#, python-format
msgid ""
"%(count)d %(type)s record skipped. Only one value per DNS record type can be "
"modified at one time."
msgid_plural ""
"%(count)d %(type)s records skipped. Only one value per DNS record type can "
"be modified at one time."
msgstr[0] ""
msgstr[1] ""

View File

@@ -0,0 +1,164 @@
# Authors:
# Rob Crittenden <rcritten@redhat.com>
# Petr Viktorin <pviktori@redhat.com>
#
# Copyright (C) 2008 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Test the `ipalib.aci` module.
"""
from __future__ import print_function
from ipalib.aci import ACI
import pytest
pytestmark = pytest.mark.tier0
def check_aci_parsing(source, expected):
a = ACI(source)
print('ACI was: ', a)
print('Expected:', expected)
assert str(ACI(source)) == expected
def test_aci_parsing_1():
check_aci_parsing('(targetattr="title")(targetfilter="(memberOf=cn=bar,cn=groups,cn=accounts ,dc=example,dc=com)")(version 3.0;acl "foobar";allow (write) groupdn="ldap:///cn=foo,cn=groups,cn=accounts,dc=example,dc=com";)',
'(targetattr = "title")(targetfilter = "(memberOf=cn=bar,cn=groups,cn=accounts ,dc=example,dc=com)")(version 3.0;acl "foobar";allow (write) groupdn = "ldap:///cn=foo,cn=groups,cn=accounts,dc=example,dc=com";)')
def test_aci_parsing_1_with_aci_keyword():
check_aci_parsing('(targetattr="title")(targetfilter="(memberOf=cn=bar,cn=groups,cn=accounts ,dc=example,dc=com)")(version 3.0;aci "foobar";allow (write) groupdn="ldap:///cn=foo,cn=groups,cn=accounts,dc=example,dc=com";)',
'(targetattr = "title")(targetfilter = "(memberOf=cn=bar,cn=groups,cn=accounts ,dc=example,dc=com)")(version 3.0;acl "foobar";allow (write) groupdn = "ldap:///cn=foo,cn=groups,cn=accounts,dc=example,dc=com";)')
def test_aci_parsing_2():
check_aci_parsing('(target="ldap:///uid=bjensen,dc=example,dc=com")(targetattr=*) (version 3.0;acl "aci1";allow (write) userdn="ldap:///self";)',
'(target = "ldap:///uid=bjensen,dc=example,dc=com")(targetattr = "*")(version 3.0;acl "aci1";allow (write) userdn = "ldap:///self";)')
def test_aci_parsing_3():
check_aci_parsing(' (targetattr = "givenName || sn || cn || displayName || title || initials || loginShell || gecos || homePhone || mobile || pager || facsimileTelephoneNumber || telephoneNumber || street || roomNumber || l || st || postalCode || manager || secretary || description || carLicense || labeledURI || inetUserHTTPURL || seeAlso || employeeType || businessCategory || ou")(version 3.0;acl "Self service";allow (write) userdn = "ldap:///self";)',
'(targetattr = "givenName || sn || cn || displayName || title || initials || loginShell || gecos || homePhone || mobile || pager || facsimileTelephoneNumber || telephoneNumber || street || roomNumber || l || st || postalCode || manager || secretary || description || carLicense || labeledURI || inetUserHTTPURL || seeAlso || employeeType || businessCategory || ou")(version 3.0;acl "Self service";allow (write) userdn = "ldap:///self";)')
def test_aci_parsing_4():
check_aci_parsing('(target="ldap:///uid=*,cn=users,cn=accounts,dc=example,dc=com")(version 3.0;acl "add_user";allow (add) groupdn="ldap:///cn=add_user,cn=taskgroups,dc=example,dc=com";)',
'(target = "ldap:///uid=*,cn=users,cn=accounts,dc=example,dc=com")(version 3.0;acl "add_user";allow (add) groupdn = "ldap:///cn=add_user,cn=taskgroups,dc=example,dc=com";)')
def test_aci_parsing_5():
check_aci_parsing('(targetattr=member)(target="ldap:///cn=ipausers,cn=groups,cn=accounts,dc=example,dc=com")(version 3.0;acl "add_user_to_default_group";allow (write) groupdn="ldap:///cn=add_user_to_default_group,cn=taskgroups,dc=example,dc=com";)',
'(target = "ldap:///cn=ipausers,cn=groups,cn=accounts,dc=example,dc=com")(targetattr = "member")(version 3.0;acl "add_user_to_default_group";allow (write) groupdn = "ldap:///cn=add_user_to_default_group,cn=taskgroups,dc=example,dc=com";)')
def test_aci_parsing_6():
check_aci_parsing('(targetattr!=member)(targe="ldap:///cn=ipausers,cn=groups,cn=accounts,dc=example,dc=com")(version 3.0;acl "add_user_to_default_group";allow (write) groupdn="ldap:///cn=add_user_to_default_group,cn=taskgroups,dc=example,dc=com";)',
'(targe = "ldap:///cn=ipausers,cn=groups,cn=accounts,dc=example,dc=com")(targetattr != "member")(version 3.0;acl "add_user_to_default_group";allow (write) groupdn = "ldap:///cn=add_user_to_default_group,cn=taskgroups,dc=example,dc=com";)')
def test_aci_parsing_7():
check_aci_parsing('(targetattr = "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "change_password"; allow (write) groupdn = "ldap:///cn=change_password,cn=taskgroups,dc=example,dc=com";)',
'(targetattr = "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0;acl "change_password";allow (write) groupdn = "ldap:///cn=change_password,cn=taskgroups,dc=example,dc=com";)')
def make_test_aci():
a = ACI()
a.name ="foo"
a.set_target_attr(['title','givenname'], "!=")
a.set_bindrule_keyword("groupdn")
a.set_bindrule_operator("=")
a.set_bindrule_expression("\"ldap:///cn=foo,cn=groups,cn=accounts,dc=example,dc=com\"")
a.permissions = ['read','write','add']
return a
def test_aci_equality():
a = make_test_aci()
print(a)
b = ACI()
b.name ="foo"
b.set_target_attr(['givenname','title'], "!=")
b.set_bindrule_keyword("groupdn")
b.set_bindrule_operator("=")
b.set_bindrule_expression("\"ldap:///cn=foo,cn=groups,cn=accounts,dc=example,dc=com\"")
b.permissions = ['add','read','write']
print(b)
assert a.isequal(b)
assert a == b
assert not a != b # pylint: disable=unneeded-not
def check_aci_inequality(b):
a = make_test_aci()
print(a)
print(b)
assert not a.isequal(b)
assert not a == b
assert a != b
def test_aci_inequality_targetattr_expression():
b = make_test_aci()
b.set_target_attr(['givenname'], "!=")
check_aci_inequality(b)
def test_aci_inequality_targetattr_op():
b = make_test_aci()
b.set_target_attr(['givenname', 'title'], "=")
check_aci_inequality(b)
def test_aci_inequality_targetfilter():
b = make_test_aci()
b.set_target_filter('(objectclass=*)', "=")
check_aci_inequality(b)
def test_aci_inequality_target():
b = make_test_aci()
b.set_target("ldap:///cn=bar,cn=groups,cn=accounts,dc=example,dc=com", "=")
check_aci_inequality(b)
def test_aci_inequality_bindrule_keyword():
b = make_test_aci()
b.set_bindrule_keyword("userdn")
check_aci_inequality(b)
def test_aci_inequality_bindrule_op():
b = make_test_aci()
b.set_bindrule_operator("!=")
check_aci_inequality(b)
def test_aci_inequality_bindrule_expression():
b = make_test_aci()
b.set_bindrule_expression("\"ldap:///cn=bar,cn=groups,cn=accounts,dc=example,dc=com\"")
check_aci_inequality(b)
def test_aci_inequality_permissions():
b = make_test_aci()
b.permissions = ['read', 'search', 'compare']
check_aci_inequality(b)
def test_aci_parsing_8():
check_aci_parsing('(targetattr != "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory || krbMKey")(version 3.0; acl "Enable Anonymous access"; allow (read, search, compare) userdn = "ldap:///anyone";)',
'(targetattr != "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory || krbMKey")(version 3.0;acl "Enable Anonymous access";allow (read,search,compare) userdn = "ldap:///anyone";)')
def test_aci_parsing_9():
check_aci_parsing('(targetfilter = "(|(objectClass=person)(objectClass=krbPrincipalAux)(objectClass=posixAccount)(objectClass=groupOfNames)(objectClass=posixGroup))")(targetattr != "aci || userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "Account Admins can manage Users and Groups"; allow (add, delete, read, write) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,dc=greyoak,dc=com";)',
'(targetattr != "aci || userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(targetfilter = "(|(objectClass=person)(objectClass=krbPrincipalAux)(objectClass=posixAccount)(objectClass=groupOfNames)(objectClass=posixGroup))")(version 3.0;acl "Account Admins can manage Users and Groups";allow (add,delete,read,write) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,dc=greyoak,dc=com";)')

View File

@@ -0,0 +1,286 @@
# Authors:
# Jason Gerard DeRose <jderose@redhat.com>
#
# Copyright (C) 2008 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Test the `ipalib.backend` module.
"""
from __future__ import print_function
# FIXME: Pylint errors
# pylint: disable=no-member
# pylint: disable=maybe-no-member
import threading
from ipatests.util import ClassChecker, raises, create_test_api
from ipatests.data import unicode_str
from ipalib.request import context, Connection
from ipalib.frontend import Command
from ipalib import backend, plugable, errors
from ipapython.version import API_VERSION
import pytest
pytestmark = pytest.mark.tier0
class test_Backend(ClassChecker):
"""
Test the `ipalib.backend.Backend` class.
"""
_cls = backend.Backend
def test_class(self):
assert self.cls.__bases__ == (plugable.Plugin,)
class Disconnect(object):
called = False
def __init__(self, id=None):
self.id = id
def __call__(self):
assert self.called is False
self.called = True
if self.id is not None:
delattr(context, self.id)
class test_Connectible(ClassChecker):
"""
Test the `ipalib.backend.Connectible` class.
"""
_cls = backend.Connectible
def test_connect(self):
"""
Test the `ipalib.backend.Connectible.connect` method.
"""
# Test that connection is created:
api = 'the api instance'
class example(self.cls):
def create_connection(self, *args, **kw):
object.__setattr__(self, 'args', args)
object.__setattr__(self, 'kw', kw)
return 'The connection.'
o = example(api, shared_instance=True)
args = ('Arg1', 'Arg2', 'Arg3')
kw = dict(key1='Val1', key2='Val2', key3='Val3')
assert not hasattr(context, 'example')
assert o.connect(*args, **kw) is None
conn = context.example
assert type(conn) is Connection
assert o.args == args
assert o.kw == kw
assert conn.conn == 'The connection.'
assert conn.disconnect == o.disconnect
# Test that Exception is raised if already connected:
m = "{0} is already connected ({1} in {2})"
e = raises(Exception, o.connect, *args, **kw)
assert str(e) == m.format(
'example', o.id, threading.currentThread().getName())
# Double check that it works after deleting context.example:
del context.example
assert o.connect(*args, **kw) is None
def test_create_connection(self):
"""
Test the `ipalib.backend.Connectible.create_connection` method.
"""
api = 'the api instance'
class example(self.cls):
pass
for klass in (self.cls, example):
o = klass(api, shared_instance=True)
e = raises(NotImplementedError, o.create_connection)
assert str(e) == '%s.create_connection()' % klass.__name__
def test_disconnect(self):
"""
Test the `ipalib.backend.Connectible.disconnect` method.
"""
api = 'the api instance'
class example(self.cls):
destroy_connection = Disconnect()
o = example(api, shared_instance=True)
m = "{0} is not connected ({1} in {2})"
e = raises(Exception, o.disconnect)
assert str(e) == m.format(
'example', o.id, threading.currentThread().getName())
context.example = 'The connection.'
assert o.disconnect() is None
assert example.destroy_connection.called is True
def test_destroy_connection(self):
"""
Test the `ipalib.backend.Connectible.destroy_connection` method.
"""
api = 'the api instance'
class example(self.cls):
pass
for klass in (self.cls, example):
o = klass(api, shared_instance=True)
e = raises(NotImplementedError, o.destroy_connection)
assert str(e) == '%s.destroy_connection()' % klass.__name__
def test_isconnected(self):
"""
Test the `ipalib.backend.Connectible.isconnected` method.
"""
api = 'the api instance'
class example(self.cls):
pass
for klass in (self.cls, example):
o = klass(api, shared_instance=True)
assert o.isconnected() is False
conn = 'whatever'
setattr(context, klass.__name__, conn)
assert o.isconnected() is True
delattr(context, klass.__name__)
def test_conn(self):
"""
Test the `ipalib.backend.Connectible.conn` property.
"""
api = 'the api instance'
msg = '{0} is not connected ({1} in {2})'
class example(self.cls):
pass
for klass in (self.cls, example):
o = klass(api, shared_instance=True)
e = raises(AttributeError, getattr, o, 'conn')
assert str(e) == msg.format(
klass.__name__, o.id, threading.currentThread().getName()
)
conn = Connection('The connection.', Disconnect())
setattr(context, klass.__name__, conn)
assert o.conn is conn.conn
delattr(context, klass.__name__)
class test_Executioner(ClassChecker):
"""
Test the `ipalib.backend.Executioner` class.
"""
_cls = backend.Executioner
def test_execute(self):
"""
Test the `ipalib.backend.Executioner.execute` method.
"""
api, _home = create_test_api(in_server=True)
class echo(Command):
takes_args = ('arg1', 'arg2+')
takes_options = ('option1?', 'option2?')
def execute(self, *args, **options):
assert type(args[1]) is tuple
return dict(result=args + (options,))
api.add_plugin(echo)
class good(Command):
def execute(self, **options):
raise errors.ValidationError(
name='nurse',
error=u'Not naughty!',
)
api.add_plugin(good)
class bad(Command):
def execute(self, **options):
raise ValueError('This is private.')
api.add_plugin(bad)
class with_name(Command):
"""
Test that a kwarg named 'name' can be used.
"""
takes_options = 'name'
def execute(self, **options):
return dict(result=options['name'].upper())
api.add_plugin(with_name)
api.finalize()
o = self.cls(api)
o.finalize()
# Test that CommandError is raised:
conn = Connection('The connection.', Disconnect('someconn'))
context.someconn = conn
print(str(list(context.__dict__)))
e = raises(errors.CommandError, o.execute, 'nope')
assert e.name == 'nope'
assert conn.disconnect.called is True # Make sure destroy_context() was called
print(str(list(context.__dict__)))
assert list(context.__dict__) == []
# Test with echo command:
arg1 = unicode_str
arg2 = (u'Hello', unicode_str, u'world!')
args = (arg1,) + arg2
options = dict(option1=u'How are you?', option2=unicode_str,
version=API_VERSION)
conn = Connection('The connection.', Disconnect('someconn'))
context.someconn = conn
print(o.execute('echo', arg1, arg2, **options))
print(dict(
result=(arg1, arg2, options)
))
assert o.execute('echo', arg1, arg2, **options) == dict(
result=(arg1, arg2, options)
)
assert conn.disconnect.called is True # Make sure destroy_context() was called
assert list(context.__dict__) == []
conn = Connection('The connection.', Disconnect('someconn'))
context.someconn = conn
assert o.execute('echo', *args, **options) == dict(
result=(arg1, arg2, options)
)
assert conn.disconnect.called is True # Make sure destroy_context() was called
assert list(context.__dict__) == []
# Test with good command:
conn = Connection('The connection.', Disconnect('someconn'))
context.someconn = conn
e = raises(errors.ValidationError, o.execute, 'good')
assert e.name == 'nurse'
assert e.error == u'Not naughty!'
assert conn.disconnect.called is True # Make sure destroy_context() was called
assert list(context.__dict__) == []
# Test with bad command:
conn = Connection('The connection.', Disconnect('someconn'))
context.someconn = conn
e = raises(errors.InternalError, o.execute, 'bad')
assert conn.disconnect.called is True # Make sure destroy_context() was called
assert list(context.__dict__) == []
# Test with option 'name':
conn = Connection('The connection.', Disconnect('someconn'))
context.someconn = conn
expected = dict(result=u'TEST')
assert expected == o.execute('with_name', name=u'test',
version=API_VERSION)

View File

@@ -0,0 +1,375 @@
# Authors:
# Jason Gerard DeRose <jderose@redhat.com>
#
# Copyright (C) 2008 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Test the `ipalib.base` module.
"""
import six
import pytest
from ipatests.util import ClassChecker, raises
from ipalib.constants import NAME_REGEX, NAME_ERROR
from ipalib.constants import TYPE_ERROR, SET_ERROR, DEL_ERROR, OVERRIDE_ERROR
from ipalib import base
if six.PY3:
unicode = str
pytestmark = pytest.mark.tier0
class test_ReadOnly(ClassChecker):
"""
Test the `ipalib.base.ReadOnly` class
"""
_cls = base.ReadOnly
def test_lock(self):
"""
Test the `ipalib.base.ReadOnly.__lock__` method.
"""
o = self.cls()
assert o._ReadOnly__locked is False
o.__lock__()
assert o._ReadOnly__locked is True
e = raises(AssertionError, o.__lock__) # Can only be locked once
assert str(e) == '__lock__() can only be called once'
assert o._ReadOnly__locked is True # This should still be True
def test_islocked(self):
"""
Test the `ipalib.base.ReadOnly.__islocked__` method.
"""
o = self.cls()
assert o.__islocked__() is False
o.__lock__()
assert o.__islocked__() is True
def test_setattr(self):
"""
Test the `ipalib.base.ReadOnly.__setattr__` method.
"""
o = self.cls()
o.attr1 = 'Hello, world!'
assert o.attr1 == 'Hello, world!'
o.__lock__()
for name in ('attr1', 'attr2'):
e = raises(AttributeError, setattr, o, name, 'whatever')
assert str(e) == SET_ERROR % ('ReadOnly', name, 'whatever')
assert o.attr1 == 'Hello, world!'
def test_delattr(self):
"""
Test the `ipalib.base.ReadOnly.__delattr__` method.
"""
o = self.cls()
o.attr1 = 'Hello, world!'
o.attr2 = 'How are you?'
assert o.attr1 == 'Hello, world!'
assert o.attr2 == 'How are you?'
del o.attr1
assert not hasattr(o, 'attr1')
o.__lock__()
e = raises(AttributeError, delattr, o, 'attr2')
assert str(e) == DEL_ERROR % ('ReadOnly', 'attr2')
assert o.attr2 == 'How are you?'
def test_lock():
"""
Test the `ipalib.base.lock` function
"""
f = base.lock
# Test with ReadOnly instance:
o = base.ReadOnly()
assert o.__islocked__() is False
assert f(o) is o
assert o.__islocked__() is True
e = raises(AssertionError, f, o)
assert str(e) == 'already locked: %r' % o
# Test with another class implemented locking protocol:
class Lockable(object):
__locked = False
def __lock__(self):
self.__locked = True
def __islocked__(self):
return self.__locked
o = Lockable()
assert o.__islocked__() is False
assert f(o) is o
assert o.__islocked__() is True
e = raises(AssertionError, f, o)
assert str(e) == 'already locked: %r' % o
# Test with a class incorrectly implementing the locking protocol:
class Broken(object):
def __lock__(self):
pass
def __islocked__(self):
return False
o = Broken()
e = raises(AssertionError, f, o)
assert str(e) == 'failed to lock: %r' % o
def test_islocked():
"""
Test the `ipalib.base.islocked` function.
"""
f = base.islocked
# Test with ReadOnly instance:
o = base.ReadOnly()
assert f(o) is False
o.__lock__()
assert f(o) is True
# Test with another class implemented locking protocol:
class Lockable(object):
__locked = False
def __lock__(self):
self.__locked = True
def __islocked__(self):
return self.__locked
o = Lockable()
assert f(o) is False
o.__lock__()
assert f(o) is True
# Test with a class incorrectly implementing the locking protocol:
class Broken(object):
__lock__ = False
def __islocked__(self):
return False
o = Broken()
e = raises(AssertionError, f, o)
assert str(e) == 'no __lock__() method: %r' % o
def test_check_name():
"""
Test the `ipalib.base.check_name` function.
"""
f = base.check_name
okay = [
'user_add',
'stuff2junk',
'sixty9',
]
nope = [
'_user_add',
'__user_add',
'user_add_',
'user_add__',
'_user_add_',
'__user_add__',
'60nine',
]
for name in okay:
assert name is f(name)
if six.PY2:
bad_type = unicode
bad_value = unicode(name)
else:
bad_type = bytes
bad_value = name.encode('ascii')
e = raises(TypeError, f, bad_value)
assert str(e) == TYPE_ERROR % ('name', str, bad_value, bad_type)
for name in nope:
e = raises(ValueError, f, name)
assert str(e) == NAME_ERROR % (NAME_REGEX, name)
for name in okay:
e = raises(ValueError, f, name.upper())
assert str(e) == NAME_ERROR % (NAME_REGEX, name.upper())
def membername(i):
return 'member%03d' % i
class DummyMember(object):
def __init__(self, i):
self.i = i
self.name = self.__name__ = membername(i)
def gen_members(*indexes):
return tuple(DummyMember(i) for i in indexes)
class test_NameSpace(ClassChecker):
"""
Test the `ipalib.base.NameSpace` class.
"""
_cls = base.NameSpace
def new(self, count, sort=True):
members = tuple(DummyMember(i) for i in range(count, 0, -1))
assert len(members) == count
o = self.cls(members, sort=sort)
return (o, members)
def test_init(self):
"""
Test the `ipalib.base.NameSpace.__init__` method.
"""
o = self.cls([])
assert len(o) == 0
assert list(o) == []
assert list(o()) == []
# Test members as attribute and item:
for cnt in (3, 42):
for sort in (True, False):
(o, members) = self.new(cnt, sort=sort)
assert len(members) == cnt
for m in members:
assert getattr(o, m.name) is m
assert o[m.name] is m
# Test that TypeError is raised if sort is not a bool:
e = raises(TypeError, self.cls, [], sort=None)
assert str(e) == TYPE_ERROR % ('sort', bool, None, type(None))
# Test that AttributeError is raised with duplicate member name:
members = gen_members(0, 1, 2, 1, 3)
e = raises(AttributeError, self.cls, members)
assert str(e) == OVERRIDE_ERROR % (
'NameSpace', membername(1), members[1], members[3]
)
def test_len(self):
"""
Test the `ipalib.base.NameSpace.__len__` method.
"""
for count in (5, 18, 127):
o, _members = self.new(count)
assert len(o) == count
o, _members = self.new(count, sort=False)
assert len(o) == count
def test_iter(self):
"""
Test the `ipalib.base.NameSpace.__iter__` method.
"""
(o, members) = self.new(25)
assert list(o) == sorted(m.name for m in members)
(o, members) = self.new(25, sort=False)
assert list(o) == list(m.name for m in members)
def test_call(self):
"""
Test the `ipalib.base.NameSpace.__call__` method.
"""
(o, members) = self.new(25)
assert list(o()) == sorted(members, key=lambda m: m.name)
(o, members) = self.new(25, sort=False)
assert tuple(o()) == members
def test_contains(self):
"""
Test the `ipalib.base.NameSpace.__contains__` method.
"""
yes = (99, 3, 777)
no = (9, 333, 77)
for sort in (True, False):
members = gen_members(*yes)
o = self.cls(members, sort=sort)
for i in yes:
assert membername(i) in o
assert membername(i).upper() not in o
assert DummyMember(i) in o
for i in no:
assert membername(i) not in o
assert DummyMember(i) not in o
def test_getitem(self):
"""
Test the `ipalib.base.NameSpace.__getitem__` method.
"""
cnt = 17
for sort in (True, False):
(o, members) = self.new(cnt, sort=sort)
assert len(members) == cnt
if sort is True:
members = tuple(sorted(members, key=lambda m: m.name))
# Test str keys:
for m in members:
assert o[m.name] is m
e = raises(KeyError, o.__getitem__, 'nope')
# Test int indexes:
for i in range(cnt):
assert o[i] is members[i]
e = raises(IndexError, o.__getitem__, cnt)
# Test negative int indexes:
for i in range(1, cnt + 1):
assert o[-i] is members[-i]
e = raises(IndexError, o.__getitem__, -(cnt + 1))
# Test slicing:
assert o[3:] == members[3:]
assert o[:10] == members[:10]
assert o[3:10] == members[3:10]
assert o[-9:] == members[-9:]
assert o[:-4] == members[:-4]
assert o[-9:-4] == members[-9:-4]
# Test retrieval by value
for member in members:
assert o[DummyMember(member.i)] is member
# Test that TypeError is raised with wrong type
e = raises(TypeError, o.__getitem__, 3.0)
assert str(e) == TYPE_ERROR % (
'key', (str, int, slice, 'object with __name__'),
3.0, float)
def test_repr(self):
"""
Test the `ipalib.base.NameSpace.__repr__` method.
"""
for cnt in (0, 1, 2):
for sort in (True, False):
o, _members = self.new(cnt, sort=sort)
if cnt == 1:
assert repr(o) == \
'NameSpace(<%d member>, sort=%r)' % (cnt, sort)
else:
assert repr(o) == \
'NameSpace(<%d members>, sort=%r)' % (cnt, sort)
def test_todict(self):
"""
Test the `ipalib.base.NameSpace.__todict__` method.
"""
for cnt in (3, 101):
for sort in (True, False):
(o, members) = self.new(cnt, sort=sort)
d = o.__todict__()
assert d == dict((m.name, m) for m in members)
# Test that a copy is returned:
assert o.__todict__() is not d

View File

@@ -0,0 +1,36 @@
# Authors:
# Petr Viktorin <pviktori@redhat.com>
#
# Copyright (C) 2012 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Test the `ipalib.errors` module.
"""
from ipalib.capabilities import capabilities, client_has_capability
import pytest
pytestmark = pytest.mark.tier0
def test_client_has_capability():
assert capabilities['messages'] == u'2.52'
assert client_has_capability(u'2.52', 'messages')
assert client_has_capability(u'2.60', 'messages')
assert client_has_capability(u'3.0', 'messages')
assert not client_has_capability(u'2.11', 'messages')
assert not client_has_capability(u'0.1', 'messages')

View File

@@ -0,0 +1,120 @@
# Authors:
# Jason Gerard DeRose <jderose@redhat.com>
#
# Copyright (C) 2008 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Test the `ipalib.cli` module.
"""
from ipatests.util import raises, ClassChecker
from ipalib import cli, plugable
import pytest
pytestmark = pytest.mark.tier0
class test_textui(ClassChecker):
_cls = cli.textui
def test_max_col_width(self):
"""
Test the `ipalib.cli.textui.max_col_width` method.
"""
api = 'the api instance'
o = self.cls(api)
e = raises(TypeError, o.max_col_width, 'hello')
assert str(e) == 'rows: need %r or %r; got %r' % (list, tuple, 'hello')
rows = [
'hello',
'naughty',
'nurse',
]
assert o.max_col_width(rows) == len('naughty')
rows = (
( 'a', 'bbb', 'ccccc'),
('aa', 'bbbb', 'cccccc'),
)
assert o.max_col_width(rows, col=0) == 2
assert o.max_col_width(rows, col=1) == 4
assert o.max_col_width(rows, col=2) == 6
def test_to_cli():
"""
Test the `ipalib.cli.to_cli` function.
"""
f = cli.to_cli
assert f('initialize') == 'initialize'
assert f('user_add') == 'user-add'
def test_from_cli():
"""
Test the `ipalib.cli.from_cli` function.
"""
f = cli.from_cli
assert f('initialize') == 'initialize'
assert f('user-add') == 'user_add'
def get_cmd_name(i):
return 'cmd_%d' % i
class DummyCommand(object):
def __init__(self, name):
self.__name = name
def __get_name(self):
return self.__name
name = property(__get_name)
class DummyAPI(object):
def __init__(self, cnt):
self.__cmd = plugable.APINameSpace(self.__cmd_iter(cnt), DummyCommand)
def __get_cmd(self):
return self.__cmd
Command = property(__get_cmd)
def __cmd_iter(self, cnt):
for i in range(cnt):
yield DummyCommand(get_cmd_name(i))
def finalize(self):
pass
def register(self, *args, **kw):
pass
config_cli = """
[global]
from_cli_conf = set in cli.conf
"""
config_default = """
[global]
from_default_conf = set in default.conf
# Make sure cli.conf is loaded first:
from_cli_conf = overridden in default.conf
"""

View File

@@ -0,0 +1,610 @@
# Authors:
# Martin Nagy <mnagy@redhat.com>
# Jason Gerard DeRose <jderose@redhat.com>
#
# Copyright (C) 2008 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Test the `ipalib.config` module.
"""
from os import path
import sys
from ipatests.util import raises, delitem, ClassChecker
from ipatests.util import getitem
from ipatests.util import TempDir, TempHome
from ipalib.constants import OVERRIDE_ERROR, SET_ERROR, DEL_ERROR
from ipalib.constants import NAME_REGEX, NAME_ERROR
from ipalib import config, constants, base
import pytest
pytestmark = pytest.mark.tier0
# Valid environment variables in (key, raw, value) tuples:
# key: the name of the environment variable
# raw: the value being set (possibly a string repr)
# value: the expected value after the lightweight conversion
good_vars = (
('a_string', u'Hello world!', u'Hello world!'),
('trailing_whitespace', u' value ', u'value'),
('an_int', 42, 42),
('int_repr', ' 42 ', 42),
('not_a_float', '3.14', u'3.14'),
('true', True, True),
('true_repr', ' True ', True),
('false', False, False),
('false_repr', ' False ', False),
('none', None, None),
('none_repr', ' None ', None),
('empty', '', None),
# These verify that the implied conversion is case-sensitive:
('not_true', u' true ', u'true'),
('not_false', u' false ', u'false'),
('not_none', u' none ', u'none'),
)
bad_names = (
('CamelCase', u'value'),
('_leading_underscore', u'value'),
('trailing_underscore_', u'value'),
)
# Random base64-encoded data to simulate a misbehaving config file.
config_bad = """
/9j/4AAQSkZJRgABAQEAlgCWAAD//gAIT2xpdmVy/9sAQwAQCwwODAoQDg0OEhEQExgoGhgWFhgx
IyUdKDozPTw5Mzg3QEhcTkBEV0U3OFBtUVdfYmdoZz5NcXlwZHhcZWdj/8AACwgAlgB0AQERAP/E
ABsAAAEFAQEAAAAAAAAAAAAAAAQAAQIDBQYH/8QAMhAAAgICAAUDBAIABAcAAAAAAQIAAwQRBRIh
MUEGE1EiMmFxFIEVI0LBFjNSYnKRof/aAAgBAQAAPwDCtzmNRr1o/MEP1D6f7kdkRakgBsAtoQhk
xls/y3Z113I11mhiUc1ewCf1Oq4anJgINdhLhQoextfedmYrenfcvdzaFQnYAE08XhONTWEK8+js
Fpo1oqAKoAA8CWjoJJTHM8kJ5jsiOiszAKD1+IV/hmW76rosbfnlh1Pp3Mah2srCnXQE9YXiel/c
p5r7uVj2CwxPTuFjjmdLbteNwmrLwsYe3TjsD8cmjKV43ycy+3o76D4llFuXmuCoZEPczXVOSsLv
f5lgGpNZLxJL2jnvMar0/wAOp6jHDH/uO4RViY9f/KpRdfC6k3R9fRyj+pRZVkWKqF10e+hCKaFq
XlH/ALlmhK7Met/uUGZ5ow8XL57lU8/Yt4lx4jUOJphLobTe/wDaHeZLxHXtJEya9o5lFzCqpmPY
CUYoPtDfc9TLj0G5jZvHaMFirAs++oEHq9U4rbNiMp8a6wO/1Zbzn2alC+Nx8P1JfdeBboA+AILx
rin8pfbA1ynvKuFUXZOXXkLbzOp2R56andL2G45MmO0RPWWLEe8GzaffoKb/ADI44Pt9ZXxAuuFa
axtgp0BOSPCcviNX8n3Aw8KTNHB4FiY9StkobLWHVSeghq8M4bkAhKKyV6Hl8RV8MwMZG1Uuz3Jn
IcUQJlMFGlJ6D4hfpymy7iChHKqvVtefxO7Ai1txLBIn7pcojN3jGVhQO0ZgCNfM5ZHycTLycSkr
yhtqD4Bmrfw5cuqsm6xHXyp1seRLcHCp4dQy1bOzslj1MzeJ5dVFnuMVdgOiHxOWzrmyMg2Nrbde
k3vR2OTddcd6A5R8GdZqOo67k4wXrLAQPMRKnzImMZEzm+P1nFz6cxQeVujagWR6jsYiqivlH/Ux
1M+7jWY30i7QHx1gF11tjGyxiSfmVc+503pPidVROHYNNY21b/adVZZySo3uOo1qIZQYd9RCzfYm
TUk/qW71LjGkTA+IYiZmM1T9N9j8Gee5+McXJem0/Wp8GUK6KOi7b5MgzFjsxpJHZGDKSCOxE3cD
OvsxbbLc9lsT7Vc73KX4ln3q1ZyVrPx2J/uAjLyan37z7B+Zp4vqPJqKi0K4EvzvUt1qBMdfb+T5
gycfzkXXuc35InfE6nO8Y9SjFc1Yqh2Hdj2mH/xFxR26XgD/AMRJf45mWMqW5bBD3KqAZlZtb++7
kEqTsHe//sG1CcTBvy7OWpD+Sewhz8CyKCTYAQPiGV0LVWPdxqQNADQ6zL4nWq2gopU6+ofmA8x3
1MlvfeIGbnBeCHitRt94IFbRGus2U9H08v13sT+BNHjeX/D4bY4OmP0rPPbHLMWJ2Yy2EDQjVsos
BdeYDx8wo5L5KpSdLWPAE1+G8NrFtBKgOAXPTf6mzViql5ZBoE87eJZkKbOQ8m+Yjf5EBzcO621y
GCqD0H41Obzq7U6vzM577HTXgzPPeOIvM1eB59nD8xXVj7bHTr8iej1MtlauvUMNgzi/V2ctliYy
HYTq37nMExpZXRZYpZVJUdzNjg+FXYwZgdhv6nVVUJU/uH7iNf1CARrtF0IB113M7jTNVjFl2xJA
5ROey88OrVOugOy67TDs+89NRKdSYILdRC8ZQVJ+PHyJs4fqe3EoFPLzBexPxOdusa2xndiWY7JM
qMUNrzOTAfHC9XO9/E3vT9blVJB0o2Zu3MAoYrsL13Ii0Muw3XvJG9KkDOeqjf6gWcw5A33XN9nX
tOeyMRFWy3Jch+bX7mXmCsW/5RBXUoHaOIRi2asAJ0IRbjqzll3o/EAaRiltDojgv2E1aePmhEWq
rsNHZ7wir1K/8Y1vUCSCAd+IXiZ9b1gLYvN07trXTUD4rxN2TkUgEts8p2NDtD0t5MVGchr2Xe99
hMPNvD1LX5J2TuZhGyYwBijjfiHU5bJXrnYfqBRtRtSbIBWG3+xI6HiLUWz8xA9RuaVNrMAPfB5x
r6v9MLr4S1il7LaxyjY69Jl5eG+Kyhiv1jYIMGYMO8etGscKoJJ8Cbp4bVg4ivaq22t3G/tmRYo5
zyjQ+JRFFET01GB0Yid9YiYh1l9KgEHqT8Tco/hewA/NzgdQdwTNGNTY3uU2crL9HN00ZlovNzfV
oCanBrBRk1rpCHPUkQjjYoW4GtwAw30MDpuxvbAvpJceR5mXFFEY0W4o4mpg0XNXutQxPUHxLb8q
7mRDyszLr6esz8u++9wL2LcvQb8RXCkhBV3A6mR5rEVSrdFPT8SBLMdsdmWe6P8AUAx+TB4oooxi
i1Jmt0+5dfuOLbANB2H6MjzNzc2zv5ji1g2+5/MYnbb+Yh+T0kubUY940UUbUWtRpJN8w1CfebkK
WfUu+/mDOAGOjsRo0UkIo+pPl6Rckl7ehuR1INGAj9u0kW2nXvK45YlQp1odukaICSAjgSQWf//Z
"""
# A config file that tries to override some standard vars:
config_override = """
[global]
key0 = var0
home = /home/sweet/home
key1 = var1
site_packages = planet
key2 = var2
key3 = var3
"""
# A config file that tests the automatic type conversion
config_good = """
[global]
string = Hello world!
null = None
yes = True
no = False
number = 42
floating = 3.14
"""
# A default config file to make sure it does not overwrite the explicit one
config_default = """
[global]
yes = Hello
not_in_other = foo_bar
"""
class test_Env(ClassChecker):
"""
Test the `ipalib.config.Env` class.
"""
_cls = config.Env
def test_init(self):
"""
Test the `ipalib.config.Env.__init__` method.
"""
o = self.cls()
assert list(o) == []
assert len(o) == 0
assert o.__islocked__() is False
def test_lock(self):
"""
Test the `ipalib.config.Env.__lock__` method.
"""
o = self.cls()
assert o.__islocked__() is False
o.__lock__()
assert o.__islocked__() is True
e = raises(Exception, o.__lock__)
assert str(e) == 'Env.__lock__() already called'
# Also test with base.lock() function:
o = self.cls()
assert o.__islocked__() is False
assert base.lock(o) is o
assert o.__islocked__() is True
e = raises(AssertionError, base.lock, o)
assert str(e) == 'already locked: %r' % o
def test_islocked(self):
"""
Test the `ipalib.config.Env.__islocked__` method.
"""
o = self.cls()
assert o.__islocked__() is False
assert base.islocked(o) is False
o.__lock__()
assert o.__islocked__() is True
assert base.islocked(o) is True
def test_setattr(self):
"""
Test the `ipalib.config.Env.__setattr__` method.
"""
o = self.cls()
for (name, raw, value) in good_vars:
# Test setting the value:
setattr(o, name, raw)
result = getattr(o, name)
assert type(result) is type(value)
assert result == value
assert result is o[name]
# Test that value cannot be overridden once set:
e = raises(AttributeError, setattr, o, name, raw)
assert str(e) == OVERRIDE_ERROR % ('Env', name, value, raw)
# Test that values cannot be set once locked:
o = self.cls()
o.__lock__()
for (name, raw, value) in good_vars:
e = raises(AttributeError, setattr, o, name, raw)
assert str(e) == SET_ERROR % ('Env', name, raw)
# Test that name is tested with check_name():
o = self.cls()
for (name, value) in bad_names:
e = raises(ValueError, setattr, o, name, value)
assert str(e) == NAME_ERROR % (NAME_REGEX, name)
def test_setitem(self):
"""
Test the `ipalib.config.Env.__setitem__` method.
"""
o = self.cls()
for (key, raw, value) in good_vars:
# Test setting the value:
o[key] = raw
result = o[key]
assert type(result) is type(value)
assert result == value
assert result is getattr(o, key)
# Test that value cannot be overridden once set:
e = raises(AttributeError, o.__setitem__, key, raw)
assert str(e) == OVERRIDE_ERROR % ('Env', key, value, raw)
# Test that values cannot be set once locked:
o = self.cls()
o.__lock__()
for (key, raw, value) in good_vars:
e = raises(AttributeError, o.__setitem__, key, raw)
assert str(e) == SET_ERROR % ('Env', key, raw)
# Test that name is tested with check_name():
o = self.cls()
for (key, value) in bad_names:
e = raises(ValueError, o.__setitem__, key, value)
assert str(e) == NAME_ERROR % (NAME_REGEX, key)
def test_getitem(self):
"""
Test the `ipalib.config.Env.__getitem__` method.
"""
o = self.cls()
value = u'some value'
o.key = value
assert o.key is value
assert o['key'] is value
for name in ('one', 'two'):
e = raises(KeyError, getitem, o, name)
assert str(e) == repr(name)
def test_delattr(self):
"""
Test the `ipalib.config.Env.__delattr__` method.
This also tests that ``__delitem__`` is not implemented.
"""
o = self.cls()
o.one = 1
assert o.one == 1
for key in ('one', 'two'):
e = raises(AttributeError, delattr, o, key)
assert str(e) == DEL_ERROR % ('Env', key)
e = raises(AttributeError, delitem, o, key)
assert str(e) == '__delitem__'
def test_contains(self):
"""
Test the `ipalib.config.Env.__contains__` method.
"""
o = self.cls()
items = [
('one', 1),
('two', 2),
('three', 3),
('four', 4),
]
for (key, value) in items:
assert key not in o
o[key] = value
assert key in o
def test_len(self):
"""
Test the `ipalib.config.Env.__len__` method.
"""
o = self.cls()
assert len(o) == 0
for i in range(1, 11):
key = 'key%d' % i
value = u'value %d' % i
o[key] = value
assert o[key] is value
assert len(o) == i
def test_iter(self):
"""
Test the `ipalib.config.Env.__iter__` method.
"""
o = self.cls()
default_keys = tuple(o)
keys = ('one', 'two', 'three', 'four', 'five')
for key in keys:
o[key] = 'the value'
assert list(o) == sorted(keys + default_keys)
def test_merge(self):
"""
Test the `ipalib.config.Env._merge` method.
"""
group1 = (
('key1', u'value 1'),
('key2', u'value 2'),
('key3', u'value 3'),
('key4', u'value 4'),
)
group2 = (
('key0', u'Value 0'),
('key2', u'Value 2'),
('key4', u'Value 4'),
('key5', u'Value 5'),
)
o = self.cls()
assert o._merge(**dict(group1)) == (4, 4)
assert len(o) == 4
assert list(o) == list(key for (key, value) in group1)
for (key, value) in group1:
assert getattr(o, key) is value
assert o[key] is value
assert o._merge(**dict(group2)) == (2, 4)
assert len(o) == 6
expected = dict(group2)
expected.update(dict(group1))
assert list(o) == sorted(expected)
assert expected['key2'] == 'value 2' # And not 'Value 2'
for (key, value) in expected.items():
assert getattr(o, key) is value
assert o[key] is value
assert o._merge(**expected) == (0, 6)
assert len(o) == 6
assert list(o) == sorted(expected)
def test_merge_from_file(self):
"""
Test the `ipalib.config.Env._merge_from_file` method.
"""
tmp = TempDir()
assert callable(tmp.join)
# Test a config file that doesn't exist
no_exist = tmp.join('no_exist.conf')
assert not path.exists(no_exist)
o = self.cls()
o._bootstrap()
keys = tuple(o)
orig = dict((k, o[k]) for k in o)
assert o._merge_from_file(no_exist) is None
assert tuple(o) == keys
# Test an empty config file
empty = tmp.touch('empty.conf')
assert path.isfile(empty)
assert o._merge_from_file(empty) == (0, 0)
assert tuple(o) == keys
# Test a mal-formed config file:
bad = tmp.join('bad.conf')
open(bad, 'w').write(config_bad)
assert path.isfile(bad)
assert o._merge_from_file(bad) is None
assert tuple(o) == keys
# Test a valid config file that tries to override
override = tmp.join('override.conf')
open(override, 'w').write(config_override)
assert path.isfile(override)
assert o._merge_from_file(override) == (4, 6)
for (k, v) in orig.items():
assert o[k] is v
assert list(o) == sorted(keys + ('key0', 'key1', 'key2', 'key3', 'config_loaded'))
for i in range(4):
assert o['key%d' % i] == ('var%d' % i)
keys = tuple(o)
# Test a valid config file with type conversion
good = tmp.join('good.conf')
open(good, 'w').write(config_good)
assert path.isfile(good)
assert o._merge_from_file(good) == (6, 6)
added = ('string', 'null', 'yes', 'no', 'number', 'floating')
assert list(o) == sorted(keys + added)
assert o.string == 'Hello world!'
assert o.null is None
assert o.yes is True
assert o.no is False
assert o.number == 42
assert o.floating == '3.14'
def new(self, in_tree=False):
"""
Set os.environ['HOME'] to a tempdir.
Returns tuple with new Env instance and the TempHome instance. This
helper method is used in testing the bootstrap related methods below.
"""
home = TempHome()
o = self.cls()
if in_tree:
o.in_tree = True
return (o, home)
def bootstrap(self, **overrides):
"""
Helper method used in testing bootstrap related methods below.
"""
(o, home) = self.new()
assert o._isdone('_bootstrap') is False
o._bootstrap(**overrides)
assert o._isdone('_bootstrap') is True
e = raises(Exception, o._bootstrap)
assert str(e) == 'Env._bootstrap() already called'
return (o, home)
def test_bootstrap(self):
"""
Test the `ipalib.config.Env._bootstrap` method.
"""
# Test defaults created by _bootstrap():
(o, home) = self.new()
o._bootstrap()
ipalib = path.dirname(path.abspath(config.__file__))
assert o.ipalib == ipalib
assert o.site_packages == path.dirname(ipalib)
assert o.script == path.abspath(sys.argv[0])
assert o.bin == path.dirname(path.abspath(sys.argv[0]))
assert o.home == home.path
assert o.dot_ipa == home.join('.ipa')
assert o.in_tree is False
assert o.context == 'default'
assert o.confdir == '/etc/ipa'
assert o.conf == '/etc/ipa/default.conf'
assert o.conf_default == o.conf
# Test overriding values created by _bootstrap()
(o, home) = self.bootstrap(in_tree='True', context='server')
assert o.in_tree is True
assert o.context == 'server'
assert o.conf == home.join('.ipa', 'server.conf')
(o, home) = self.bootstrap(conf='/my/wacky/whatever.conf')
assert o.in_tree is False
assert o.context == 'default'
assert o.conf == '/my/wacky/whatever.conf'
assert o.conf_default == '/etc/ipa/default.conf'
(o, home) = self.bootstrap(conf_default='/my/wacky/default.conf')
assert o.in_tree is False
assert o.context == 'default'
assert o.conf == '/etc/ipa/default.conf'
assert o.conf_default == '/my/wacky/default.conf'
# Test various overrides and types conversion
kw = dict(
yes=True,
no=False,
num=42,
msg='Hello, world!',
)
override = dict(
(k, u' %s ' % v) for (k, v) in kw.items()
)
(o, home) = self.new()
for key in kw:
assert key not in o
o._bootstrap(**override)
for (key, value) in kw.items():
assert getattr(o, key) == value
assert o[key] == value
def finalize_core(self, ctx, **defaults):
"""
Helper method used in testing `Env._finalize_core`.
"""
# We must force in_tree=True so we don't load possible config files in
# /etc/ipa/, whose contents could break this test:
(o, home) = self.new(in_tree=True)
if ctx:
o.context = ctx
# Check that calls cascade down the chain:
set_here = ('in_server', 'logdir', 'log')
assert o._isdone('_bootstrap') is False
assert o._isdone('_finalize_core') is False
assert o._isdone('_finalize') is False
for key in set_here:
assert key not in o
o._finalize_core(**defaults)
assert o._isdone('_bootstrap') is True
assert o._isdone('_finalize_core') is True
assert o._isdone('_finalize') is False # Should not cascade
for key in set_here:
assert key in o
# Check that it can't be called twice:
e = raises(Exception, o._finalize_core)
assert str(e) == 'Env._finalize_core() already called'
return (o, home)
def test_finalize_core(self):
"""
Test the `ipalib.config.Env._finalize_core` method.
"""
# Test that correct defaults are generated:
(o, home) = self.finalize_core(None)
assert o.in_server is False
assert o.logdir == home.join('.ipa', 'log')
assert o.log == home.join('.ipa', 'log', 'default.log')
# Test with context='server'
(o, home) = self.finalize_core('server')
assert o.in_server is True
assert o.logdir == home.join('.ipa', 'log')
assert o.log == home.join('.ipa', 'log', 'server.log')
# Test that **defaults can't set in_server, logdir, nor log:
(o, home) = self.finalize_core(None,
in_server='IN_SERVER',
logdir='LOGDIR',
log='LOG',
)
assert o.in_server is False
assert o.logdir == home.join('.ipa', 'log')
assert o.log == home.join('.ipa', 'log', 'default.log')
# Test loading config file, plus test some in-tree stuff
(o, home) = self.bootstrap(in_tree=True, context='server')
for key in ('yes', 'no', 'number'):
assert key not in o
home.write(config_good, '.ipa', 'server.conf')
home.write(config_default, '.ipa', 'default.conf')
o._finalize_core()
assert o.in_tree is True
assert o.context == 'server'
assert o.in_server is True
assert o.logdir == home.join('.ipa', 'log')
assert o.log == home.join('.ipa', 'log', 'server.log')
assert o.yes is True
assert o.no is False
assert o.number == 42
assert o.not_in_other == 'foo_bar'
# Test using DEFAULT_CONFIG:
defaults = dict(constants.DEFAULT_CONFIG)
(o, home) = self.finalize_core(None, **defaults)
list_o = [key for key in o if key != 'fips_mode']
assert list_o == sorted(defaults)
for (key, value) in defaults.items():
if value is object:
continue
if key == 'mode':
continue
assert o[key] == value, '%r is %r; should be %r' % (key, o[key], value)
def test_finalize(self):
"""
Test the `ipalib.config.Env._finalize` method.
"""
# Check that calls cascade up the chain:
o, _home = self.new(in_tree=True)
assert o._isdone('_bootstrap') is False
assert o._isdone('_finalize_core') is False
assert o._isdone('_finalize') is False
o._finalize()
assert o._isdone('_bootstrap') is True
assert o._isdone('_finalize_core') is True
assert o._isdone('_finalize') is True
# Check that it can't be called twice:
e = raises(Exception, o._finalize)
assert str(e) == 'Env._finalize() already called'
# Check that _finalize() calls __lock__()
o, _home = self.new(in_tree=True)
assert o.__islocked__() is False
o._finalize()
assert o.__islocked__() is True
e = raises(Exception, o.__lock__)
assert str(e) == 'Env.__lock__() already called'
# Check that **lastchance works
o, _home = self.finalize_core(None)
key = 'just_one_more_key'
value = u'with one more value'
lastchance = {key: value}
assert key not in o
assert o._isdone('_finalize') is False
o._finalize(**lastchance)
assert key in o
assert o[key] is value

View File

@@ -0,0 +1,244 @@
# Authors:
# Jason Gerard DeRose <jderose@redhat.com>
#
# Copyright (C) 2008 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Test the `ipalib.crud` module.
"""
from ipatests.util import raises, get_api, ClassChecker
from ipalib import crud, frontend
from ipalib.parameters import Str
import pytest
pytestmark = pytest.mark.tier0
class CrudChecker(ClassChecker):
"""
Class for testing base classes in `ipalib.crud`.
"""
def get_api(self, args=tuple(), options=tuple()):
"""
Return a finalized `ipalib.plugable.API` instance.
"""
api, _home = get_api()
class user(frontend.Object):
takes_params = (
'givenname',
Str('sn', flags='no_update'),
Str('uid', primary_key=True),
'initials',
Str('uidnumber', flags=['no_create', 'no_search'])
)
class user_verb(self.cls):
takes_args = args
takes_options = options
api.add_plugin(user)
api.add_plugin(user_verb)
api.finalize()
return api
class test_Create(CrudChecker):
"""
Test the `ipalib.crud.Create` class.
"""
_cls = crud.Create
def test_get_args(self):
"""
Test the `ipalib.crud.Create.get_args` method.
"""
api = self.get_api()
assert list(api.Method.user_verb.args) == ['uid']
assert api.Method.user_verb.args.uid.required is True
def test_get_options(self):
"""
Test the `ipalib.crud.Create.get_options` method.
"""
api = self.get_api()
assert list(api.Method.user_verb.options) == \
['givenname', 'sn', 'initials', 'all', 'raw', 'version']
for param in api.Method.user_verb.options():
if param.name != 'version':
assert param.required is True
api = self.get_api(options=(Str('extra?'),))
assert list(api.Method.user_verb.options) == \
['givenname', 'sn', 'initials', 'extra', 'all', 'raw', 'version']
assert api.Method.user_verb.options.extra.required is False
class test_Update(CrudChecker):
"""
Test the `ipalib.crud.Update` class.
"""
_cls = crud.Update
def test_get_args(self):
"""
Test the `ipalib.crud.Update.get_args` method.
"""
api = self.get_api()
assert list(api.Method.user_verb.args) == ['uid']
assert api.Method.user_verb.args.uid.required is True
def test_get_options(self):
"""
Test the `ipalib.crud.Update.get_options` method.
"""
api = self.get_api()
assert list(api.Method.user_verb.options) == \
['givenname', 'initials', 'uidnumber', 'all', 'raw', 'version']
for param in api.Method.user_verb.options():
if param.name in ['all', 'raw']:
assert param.required is True
else:
assert param.required is False
class test_Retrieve(CrudChecker):
"""
Test the `ipalib.crud.Retrieve` class.
"""
_cls = crud.Retrieve
def test_get_args(self):
"""
Test the `ipalib.crud.Retrieve.get_args` method.
"""
api = self.get_api()
assert list(api.Method.user_verb.args) == ['uid']
assert api.Method.user_verb.args.uid.required is True
def test_get_options(self):
"""
Test the `ipalib.crud.Retrieve.get_options` method.
"""
api = self.get_api()
assert list(api.Method.user_verb.options) == ['all', 'raw', 'version']
class test_Delete(CrudChecker):
"""
Test the `ipalib.crud.Delete` class.
"""
_cls = crud.Delete
def test_get_args(self):
"""
Test the `ipalib.crud.Delete.get_args` method.
"""
api = self.get_api()
assert list(api.Method.user_verb.args) == ['uid']
assert api.Method.user_verb.args.uid.required is True
def test_get_options(self):
"""
Test the `ipalib.crud.Delete.get_options` method.
"""
api = self.get_api()
assert list(api.Method.user_verb.options) == ['version']
assert len(api.Method.user_verb.options) == 1
class test_Search(CrudChecker):
"""
Test the `ipalib.crud.Search` class.
"""
_cls = crud.Search
def test_get_args(self):
"""
Test the `ipalib.crud.Search.get_args` method.
"""
api = self.get_api()
assert list(api.Method.user_verb.args) == ['criteria']
assert api.Method.user_verb.args.criteria.required is False
def test_get_options(self):
"""
Test the `ipalib.crud.Search.get_options` method.
"""
api = self.get_api()
assert list(api.Method.user_verb.options) == \
['givenname', 'sn', 'uid', 'initials', 'all', 'raw', 'version']
for param in api.Method.user_verb.options():
if param.name in ['all', 'raw']:
assert param.required is True
else:
assert param.required is False
class test_CrudBackend(ClassChecker):
"""
Test the `ipalib.crud.CrudBackend` class.
"""
_cls = crud.CrudBackend
def get_subcls(self):
class ldap(self.cls):
pass
return ldap
def check_method(self, name, *args):
api = 'the api instance'
o = self.cls(api)
e = raises(NotImplementedError, getattr(o, name), *args)
assert str(e) == 'CrudBackend.%s()' % name
sub = self.subcls(api)
e = raises(NotImplementedError, getattr(sub, name), *args)
assert str(e) == 'ldap.%s()' % name
def test_create(self):
"""
Test the `ipalib.crud.CrudBackend.create` method.
"""
self.check_method('create')
def test_retrieve(self):
"""
Test the `ipalib.crud.CrudBackend.retrieve` method.
"""
self.check_method('retrieve', 'primary key', 'attribute')
def test_update(self):
"""
Test the `ipalib.crud.CrudBackend.update` method.
"""
self.check_method('update', 'primary key')
def test_delete(self):
"""
Test the `ipalib.crud.CrudBackend.delete` method.
"""
self.check_method('delete', 'primary key')
def test_search(self):
"""
Test the `ipalib.crud.CrudBackend.search` method.
"""
self.check_method('search')

View File

@@ -0,0 +1,377 @@
# Authors:
# Jason Gerard DeRose <jderose@redhat.com>
#
# Copyright (C) 2008 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Test the `ipalib.errors` module.
"""
# FIXME: Pylint errors
# pylint: disable=no-member
import re
import inspect
import pytest
import six
from ipatests.util import assert_equal, raises
from ipalib import errors
from ipalib.constants import TYPE_ERROR
if six.PY3:
unicode = str
pytestmark = pytest.mark.tier0
class PrivateExceptionTester(object):
_klass = None
__klass = None
def __get_klass(self):
if self.__klass is None:
self.__klass = self._klass
assert issubclass(self.__klass, Exception)
assert issubclass(self.__klass, errors.PrivateError)
assert not issubclass(self.__klass, errors.PublicError)
return self.__klass
klass = property(__get_klass)
def new(self, **kw):
for (key, value) in kw.items():
assert not hasattr(self.klass, key), key
inst = self.klass(**kw)
assert isinstance(inst, Exception)
assert isinstance(inst, errors.PrivateError)
assert isinstance(inst, self.klass)
assert not isinstance(inst, errors.PublicError)
for (key, value) in kw.items():
assert getattr(inst, key) is value
assert str(inst) == self.klass.format % kw
return inst
class test_PrivateError(PrivateExceptionTester):
"""
Test the `ipalib.errors.PrivateError` exception.
"""
_klass = errors.PrivateError
def test_init(self):
"""
Test the `ipalib.errors.PrivateError.__init__` method.
"""
inst = self.klass(key1='Value 1', key2='Value 2')
assert inst.key1 == 'Value 1'
assert inst.key2 == 'Value 2'
assert str(inst) == ''
# Test subclass and use of format:
class subclass(self.klass):
format = '%(true)r %(text)r %(number)r'
kw = dict(true=True, text='Hello!', number=18)
inst = subclass(**kw)
assert inst.true is True
assert inst.text is kw['text']
assert inst.number is kw['number']
assert str(inst) == subclass.format % kw
# Test via PrivateExceptionTester.new()
inst = self.new(**kw)
assert isinstance(inst, self.klass)
assert inst.true is True
assert inst.text is kw['text']
assert inst.number is kw['number']
class test_SubprocessError(PrivateExceptionTester):
"""
Test the `ipalib.errors.SubprocessError` exception.
"""
_klass = errors.SubprocessError
def test_init(self):
"""
Test the `ipalib.errors.SubprocessError.__init__` method.
"""
bin_false = '/bin/false'
inst = self.new(returncode=1, argv=(bin_false,))
assert inst.returncode == 1
assert inst.argv == (bin_false,)
assert str(inst) == "return code 1 from ('{}',)".format(bin_false)
class test_PluginSubclassError(PrivateExceptionTester):
"""
Test the `ipalib.errors.PluginSubclassError` exception.
"""
_klass = errors.PluginSubclassError
def test_init(self):
"""
Test the `ipalib.errors.PluginSubclassError.__init__` method.
"""
inst = self.new(plugin='bad', bases=('base1', 'base2'))
assert inst.plugin == 'bad'
assert inst.bases == ('base1', 'base2')
assert str(inst) == \
"'bad' not subclass of any base in ('base1', 'base2')"
class test_PluginDuplicateError(PrivateExceptionTester):
"""
Test the `ipalib.errors.PluginDuplicateError` exception.
"""
_klass = errors.PluginDuplicateError
def test_init(self):
"""
Test the `ipalib.errors.PluginDuplicateError.__init__` method.
"""
inst = self.new(plugin='my_plugin')
assert inst.plugin == 'my_plugin'
assert str(inst) == "'my_plugin' was already registered"
class test_PluginOverrideError(PrivateExceptionTester):
"""
Test the `ipalib.errors.PluginOverrideError` exception.
"""
_klass = errors.PluginOverrideError
def test_init(self):
"""
Test the `ipalib.errors.PluginOverrideError.__init__` method.
"""
inst = self.new(base='Base', name='cmd', plugin='my_cmd')
assert inst.base == 'Base'
assert inst.name == 'cmd'
assert inst.plugin == 'my_cmd'
assert str(inst) == "unexpected override of Base.cmd with 'my_cmd'"
class test_PluginMissingOverrideError(PrivateExceptionTester):
"""
Test the `ipalib.errors.PluginMissingOverrideError` exception.
"""
_klass = errors.PluginMissingOverrideError
def test_init(self):
"""
Test the `ipalib.errors.PluginMissingOverrideError.__init__` method.
"""
inst = self.new(base='Base', name='cmd', plugin='my_cmd')
assert inst.base == 'Base'
assert inst.name == 'cmd'
assert inst.plugin == 'my_cmd'
assert str(inst) == "Base.cmd not registered, cannot override with 'my_cmd'"
##############################################################################
# Unit tests for public errors:
class PublicExceptionTester(object):
_klass = None
__klass = None
def __get_klass(self):
if self.__klass is None:
self.__klass = self._klass
assert issubclass(self.__klass, Exception)
assert issubclass(self.__klass, errors.PublicError)
assert not issubclass(self.__klass, errors.PrivateError)
assert type(self.__klass.errno) is int
assert 900 <= self.__klass.errno <= 5999
return self.__klass
klass = property(__get_klass)
def new(self, format=None, message=None, **kw):
# Test that TypeError is raised if message isn't unicode:
e = raises(TypeError, self.klass, message=b'The message')
assert str(e) == TYPE_ERROR % ('message', unicode, b'The message', bytes)
# Test the instance:
for (key, value) in kw.items():
assert not hasattr(self.klass, key), key
inst = self.klass(format=format, message=message, **kw)
for required_class in self.required_classes:
assert isinstance(inst, required_class)
assert isinstance(inst, self.klass)
assert not isinstance(inst, errors.PrivateError)
for (key, value) in kw.items():
assert getattr(inst, key) is value
return inst
class test_PublicError(PublicExceptionTester):
"""
Test the `ipalib.errors.PublicError` exception.
"""
_klass = errors.PublicError
required_classes = Exception, errors.PublicError
def test_init(self):
message = u'The translated, interpolated message'
format = 'key=%(key1)r and key2=%(key2)r'
val1 = u'Value 1'
val2 = u'Value 2'
kw = dict(key1=val1, key2=val2)
# Test with format=str, message=None
inst = self.klass(format, **kw)
assert inst.format is format
assert_equal(str(inst), format % kw)
assert inst.forwarded is False
assert inst.key1 is val1
assert inst.key2 is val2
# Test with format=None, message=unicode
inst = self.klass(message=message, **kw)
assert inst.format is None
assert str(inst) == message
assert inst.strerror is message
assert inst.forwarded is True
assert inst.key1 is val1
assert inst.key2 is val2
# Test with format=None, message=bytes
e = raises(TypeError, self.klass, message=b'the message', **kw)
assert str(e) == TYPE_ERROR % ('message', unicode, b'the message', bytes)
# Test with format=None, message=None
e = raises(ValueError, self.klass, **kw)
assert (str(e) == '%s.format is None yet format=None, message=None' %
self.klass.__name__)
######################################
# Test via PublicExceptionTester.new()
# Test with format=str, message=None
inst = self.new(format, **kw)
assert isinstance(inst, self.klass)
assert inst.format is format
assert_equal(str(inst), format % kw)
assert inst.forwarded is False
assert inst.key1 is val1
assert inst.key2 is val2
# Test with format=None, message=unicode
inst = self.new(message=message, **kw)
assert isinstance(inst, self.klass)
assert inst.format is None
assert str(inst) == message
assert inst.strerror is message
assert inst.forwarded is True
assert inst.key1 is val1
assert inst.key2 is val2
##################
# Test a subclass:
class subclass(self.klass):
format = '%(true)r %(text)r %(number)r'
kw = dict(true=True, text=u'Hello!', number=18)
# Test with format=str, message=None
e = raises(ValueError, subclass, format, **kw)
assert str(e) == 'non-generic %r needs format=None; got format=%r' % (
'subclass', format)
# Test with format=None, message=None:
inst = subclass(**kw)
assert inst.format is subclass.format
assert_equal(str(inst), subclass.format % kw)
assert inst.forwarded is False
assert inst.true is True
assert inst.text is kw['text']
assert inst.number is kw['number']
# Test with format=None, message=unicode:
inst = subclass(message=message, **kw)
assert inst.format is subclass.format
assert str(inst) == message
assert inst.strerror is message
assert inst.forwarded is True
assert inst.true is True
assert inst.text is kw['text']
assert inst.number is kw['number']
# Test with instructions:
# first build up "instructions", then get error and search for
# lines of instructions appended to the end of the strerror
# despite the parameter 'instructions' not existing in the format
instructions = u"The quick brown fox jumps over the lazy dog".split()
# this expression checks if each word of instructions
# exists in a string as a separate line, with right order
regexp = re.compile('(?ims).*' +
''.join('(%s).*' % (x) for x in instructions) +
'$')
inst = subclass(instructions=instructions, **kw)
assert inst.format is subclass.format
assert_equal(inst.instructions, unicode(instructions))
inst_match = regexp.match(inst.strerror).groups()
assert_equal(list(inst_match),list(instructions))
class BaseMessagesTest(object):
"""Generic test for all of a module's errors or messages
"""
def test_public_messages(self):
i = 0
for klass in self.message_list:
for required_class in self.required_classes:
assert issubclass(klass, required_class)
assert type(klass.errno) is int
assert klass.errno in self.errno_range
doc = inspect.getdoc(klass)
assert doc is not None, 'need class docstring for %s' % klass.__name__
m = re.match(r'^\*{2}(\d+)\*{2} ', doc)
assert m is not None, "need '**ERRNO**' in %s docstring" % klass.__name__
errno = int(m.group(1))
assert errno == klass.errno, (
'docstring=%r but errno=%r in %s' % (errno, klass.errno, klass.__name__)
)
self.extratest(klass)
# Test format
if klass.format is not None:
assert klass.format is self.texts[i]
i += 1
def extratest(self, cls):
pass
class test_PublicErrors(object):
message_list = errors.public_errors
errno_range = list(range(900, 5999))
required_classes = (Exception, errors.PublicError)
texts = errors._texts
def extratest(self, cls):
assert not issubclass(cls, errors.PrivateError)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,95 @@
# Authors:
# Petr Viktorin <pviktori@redhat.com>
#
# Copyright (C) 1012 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Test the `ipalib.messages` module.
"""
from ipalib import messages
from ipalib.capabilities import capabilities
from ipatests.test_ipalib import test_errors
import pytest
pytestmark = pytest.mark.tier0
class HelloMessage(messages.PublicMessage):
type = 'info'
format = '%(greeting)s, %(object)s!'
errno = 1234
class test_PublicMessage(test_errors.test_PublicError):
"""Test public messages"""
# The messages are a lot like public errors; defer testing to that.
klass = messages.PublicMessage
required_classes = (UserWarning, messages.PublicMessage)
class test_PublicMessages(test_errors.BaseMessagesTest):
message_list = messages.public_messages
errno_range = list(range(10000, 19999))
required_classes = (UserWarning, messages.PublicMessage)
texts = messages._texts
def extratest(self, cls):
if cls is not messages.PublicMessage:
assert cls.type in ('debug', 'info', 'warning', 'error')
def test_to_dict():
expected = dict(
name=u'HelloMessage',
type=u'info',
message=u'Hello, world!',
code=1234,
data={'greeting': 'Hello', 'object': 'world'},
)
assert HelloMessage(greeting='Hello', object='world').to_dict() == expected
def test_add_message():
result = {}
assert capabilities['messages'] == u'2.52'
messages.add_message(u'2.52', result,
HelloMessage(greeting='Hello', object='world'))
messages.add_message(u'2.1', result,
HelloMessage(greeting="'Lo", object='version'))
messages.add_message(u'2.60', result,
HelloMessage(greeting='Hi', object='version'))
assert result == {'messages': [
dict(
name=u'HelloMessage',
type=u'info',
message=u'Hello, world!',
code=1234,
data={'greeting': 'Hello', 'object': 'world'},
),
dict(
name=u'HelloMessage',
type=u'info',
message=u'Hi, version!',
code=1234,
data={'greeting': 'Hi', 'object': 'version'},
)
]}

View File

@@ -0,0 +1,96 @@
# Authors:
# Jason Gerard DeRose <jderose@redhat.com>
#
# Copyright (C) 2009 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Test the `ipalib.output` module.
"""
from ipatests.util import raises, ClassChecker
from ipalib import output
from ipalib.frontend import Command
from ipapython.version import API_VERSION
import pytest
pytestmark = pytest.mark.tier0
class test_Output(ClassChecker):
"""
Test the `ipalib.output.Output` class.
"""
_cls = output.Output
def test_init(self):
"""
Test the `ipalib.output.Output.__init__` method.
"""
o = self.cls('result')
assert o.name == 'result'
assert o.type is None
assert o.doc is None
def test_repr(self):
"""
Test the `ipalib.output.Output.__repr__` method.
"""
o = self.cls('aye')
assert repr(o) == "Output('aye')"
o = self.cls('aye', type=int, doc='An A, aye?')
assert repr(o) == "Output('aye', type=[%r], doc='An A, aye?')" % int
class Entry(self.cls):
pass
o = Entry('aye')
assert repr(o) == "Entry('aye')"
o = Entry('aye', type=int, doc='An A, aye?')
assert repr(o) == "Entry('aye', type=[%r], doc='An A, aye?')" % int
class test_ListOfEntries(ClassChecker):
"""
Test the `ipalib.output.ListOfEntries` class.
"""
_cls = output.ListOfEntries
def test_validate(self):
"""
Test the `ipalib.output.ListOfEntries.validate` method.
"""
api = 'the api instance'
class example(Command):
pass
cmd = example(api)
inst = self.cls('stuff')
okay = dict(foo='bar')
nope = ('aye', 'bee')
e = raises(TypeError, inst.validate,
cmd, [okay, okay, nope], API_VERSION)
assert str(e) == output.emsg % (
'example', 'ListOfEntries', 'stuff', 2, dict, tuple, nope
)
e = raises(TypeError, inst.validate,
cmd, [nope, okay, nope], API_VERSION)
assert str(e) == output.emsg % (
'example', 'ListOfEntries', 'stuff', 0, dict, tuple, nope
)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,309 @@
# Authors:
# Jason Gerard DeRose <jderose@redhat.com>
#
# Copyright (C) 2008 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Test the `ipalib.plugable` module.
"""
# FIXME: Pylint errors
# pylint: disable=no-member
import os
import textwrap
from ipalib import plugable, errors, create_api
from ipatests.util import raises, read_only
from ipatests.util import ClassChecker, create_test_api, TempHome
import pytest
pytestmark = pytest.mark.tier0
class test_Plugin(ClassChecker):
"""
Test the `ipalib.plugable.Plugin` class.
"""
_cls = plugable.Plugin
def test_class(self):
"""
Test the `ipalib.plugable.Plugin` class.
"""
assert self.cls.__bases__ == (plugable.ReadOnly,)
assert type(self.cls.api) is property
def test_init(self):
"""
Test the `ipalib.plugable.Plugin.__init__` method.
"""
api = 'the api instance'
o = self.cls(api)
assert o.name == 'Plugin'
assert isinstance(o.doc, str)
class some_subclass(self.cls):
"""
Do sub-classy things.
Although it doesn't know how to comport itself and is not for mixed
company, this class *is* useful as we all need a little sub-class
now and then.
One more paragraph.
"""
o = some_subclass(api)
assert o.name == 'some_subclass'
assert o.summary == 'Do sub-classy things.'
assert isinstance(o.doc, str)
class another_subclass(self.cls):
pass
o = another_subclass(api)
assert o.summary == u'<%s.%s>' % (another_subclass.__module__,
another_subclass.__name__)
# Test that Plugin makes sure the subclass hasn't defined attributes
# whose names conflict with the logger methods set in Plugin.__init__():
class check(self.cls):
info = 'whatever'
e = raises(Exception, check, api)
assert str(e) == \
"info is already bound to ipatests.test_ipalib.test_plugable.check()"
def test_finalize(self):
"""
Test the `ipalib.plugable.Plugin.finalize` method.
"""
class api(object):
@staticmethod
def is_production_mode():
return False
o = self.cls(api)
assert not o.__islocked__()
o.finalize()
assert o.__islocked__()
def test_Registry():
"""
Test the `ipalib.plugable.Registry` class
"""
class Base1(object):
pass
class Base2(object):
pass
class plugin1(Base1):
pass
class plugin2(Base2):
pass
# Test creation of Registry:
r = plugable.Registry()
# Check that TypeError is raised trying to register something that isn't
# a class:
p = plugin1()
e = raises(TypeError, r(), p)
assert str(e) == 'plugin must be callable; got %r' % p
# Check that registration works
r()(plugin1)
# Check that DuplicateError is raised trying to register exact class
# again:
e = raises(errors.PluginDuplicateError, r(), plugin1)
assert e.plugin is plugin1
# Check that overriding works
class base1_extended(Base1):
pass
class plugin1(base1_extended): # pylint: disable=function-redefined
pass
r(override=True)(plugin1)
# Test that another plugin can be registered:
r()(plugin2)
# Setup to test more registration:
class plugin1a(Base1):
pass
r()(plugin1a)
class plugin1b(Base1):
pass
r()(plugin1b)
class plugin2a(Base2):
pass
r()(plugin2a)
class plugin2b(Base2):
pass
r()(plugin2b)
class test_API(ClassChecker):
"""
Test the `ipalib.plugable.API` class.
"""
_cls = plugable.API
def test_API(self):
"""
Test the `ipalib.plugable.API` class.
"""
assert issubclass(plugable.API, plugable.ReadOnly)
# Setup the test bases, create the API:
class base0(plugable.Plugin):
def method(self, n):
return n
class base1(plugable.Plugin):
def method(self, n):
return n + 1
class API(plugable.API):
bases = (base0, base1)
modules = ()
api = API()
api.env.mode = 'unit_test'
api.env.in_tree = True
r = api.add_plugin
class base0_plugin0(base0):
pass
r(base0_plugin0)
class base0_plugin1(base0):
pass
r(base0_plugin1)
class base0_plugin2(base0):
pass
r(base0_plugin2)
class base1_plugin0(base1):
pass
r(base1_plugin0)
class base1_plugin1(base1):
pass
r(base1_plugin1)
class base1_plugin2(base1):
pass
r(base1_plugin2)
# Test API instance:
assert api.isdone('bootstrap') is False
assert api.isdone('finalize') is False
api.finalize()
assert api.isdone('bootstrap') is True
assert api.isdone('finalize') is True
def get_base_name(b):
return 'base%d' % b
def get_plugin_name(b, p):
return 'base%d_plugin%d' % (b, p)
for b in range(2):
base_name = get_base_name(b)
base = locals()[base_name]
ns = getattr(api, base_name)
assert isinstance(ns, plugable.APINameSpace)
assert read_only(api, base_name) is ns
assert len(ns) == 3
for p in range(3):
plugin_name = get_plugin_name(b, p)
plugin = locals()[plugin_name]
inst = ns[plugin_name]
assert isinstance(inst, base)
assert isinstance(inst, plugin)
assert inst.name == plugin_name
assert inst.method(7) == 7 + b
# Test that calling finilize again raises AssertionError:
e = raises(Exception, api.finalize)
assert str(e) == 'API.finalize() already called', str(e)
def test_bootstrap(self):
"""
Test the `ipalib.plugable.API.bootstrap` method.
"""
o, _home = create_test_api()
assert o.env._isdone('_bootstrap') is False
assert o.env._isdone('_finalize_core') is False
assert o.isdone('bootstrap') is False
o.bootstrap(my_test_override='Hello, world!')
assert o.isdone('bootstrap') is True
assert o.env._isdone('_bootstrap') is True
assert o.env._isdone('_finalize_core') is True
assert o.env.my_test_override == 'Hello, world!'
e = raises(Exception, o.bootstrap)
assert str(e) == 'API.bootstrap() already called'
def test_load_plugins(self):
"""
Test the `ipalib.plugable.API.load_plugins` method.
"""
o, _home = create_test_api()
assert o.isdone('bootstrap') is False
assert o.isdone('load_plugins') is False
o.load_plugins()
assert o.isdone('bootstrap') is True
assert o.isdone('load_plugins') is True
e = raises(Exception, o.load_plugins)
assert str(e) == 'API.load_plugins() already called'
def test_ipaconf_env(self):
ipa_confdir = os.environ.get('IPA_CONFDIR', None)
try:
with TempHome() as home:
defaultconf = home.join('default.conf')
with open(defaultconf, 'w') as f:
f.write(textwrap.dedent("""
[global]
basedn = dc=ipa,dc=test
realm = IPA.TEST
domain = ipa.test
""")
)
os.environ['IPA_CONFDIR'] = home.path
api = create_api(mode='unit_test')
api.bootstrap()
api.finalize()
assert api.env.confdir == home.path
assert api.env.conf_default == defaultconf
assert api.env.realm == 'IPA.TEST'
assert api.env.domain == 'ipa.test'
os.environ['IPA_CONFDIR'] = home.join('invalid')
api = create_api(mode='unit_test')
with pytest.raises(errors.EnvironmentError):
api.bootstrap()
finally:
if ipa_confdir:
os.environ['IPA_CONFDIR'] = ipa_confdir
else:
os.environ.pop('IPA_CONFDIR')

View File

@@ -0,0 +1,397 @@
# Authors:
# Jason Gerard DeRose <jderose@redhat.com>
#
# Copyright (C) 2008 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Test the `ipalib.rpc` module.
"""
from __future__ import print_function
import nose
import pytest
import six
# pylint: disable=import-error
from six.moves.xmlrpc_client import Binary, Fault, dumps, loads
# pylint: enable=import-error
from six.moves import urllib
from ipatests.util import raises, assert_equal, PluginTester, DummyClass
from ipatests.util import Fuzzy
from ipatests.data import binary_bytes, utf8_bytes, unicode_str
from ipalib.frontend import Command
from ipalib.request import context, Connection
from ipalib import rpc, errors, api, request
from ipapython.version import API_VERSION
if six.PY3:
unicode = str
std_compound = (binary_bytes, utf8_bytes, unicode_str)
def dump_n_load(value):
param, _method = loads(
dumps((value,), allow_none=True)
)
return param[0]
def round_trip(value):
return rpc.xml_unwrap(
dump_n_load(rpc.xml_wrap(value, API_VERSION))
)
def test_round_trip():
"""
Test `ipalib.rpc.xml_wrap` and `ipalib.rpc.xml_unwrap`.
This tests the two functions together with ``xmlrpc.client.dumps()`` and
``xmlrpc.client.loads()`` in a full wrap/dumps/loads/unwrap round trip.
"""
# We first test that our assumptions about xmlrpc.client module in the Python
# standard library are correct:
if six.PY2:
output_binary_type = bytes
else:
output_binary_type = Binary
if six.PY2:
assert_equal(dump_n_load(utf8_bytes), unicode_str)
assert_equal(dump_n_load(unicode_str), unicode_str)
# "Binary" is not "str". pylint: disable=no-member
assert_equal(dump_n_load(Binary(binary_bytes)).data, binary_bytes)
assert isinstance(dump_n_load(Binary(binary_bytes)), Binary)
assert type(dump_n_load(b'hello')) is output_binary_type
assert type(dump_n_load(u'hello')) is str
assert_equal(dump_n_load(b''), output_binary_type(b''))
assert_equal(dump_n_load(u''), str())
assert dump_n_load(None) is None
# Now we test our wrap and unwrap methods in combination with dumps, loads:
# All bytes should come back bytes (because they get wrapped in
# xmlrpc.client.Binary(). All unicode should come back unicode because str
# explicity get decoded by rpc.xml_unwrap() if they weren't already
# decoded by xmlrpc.client.loads().
assert_equal(round_trip(utf8_bytes), utf8_bytes)
assert_equal(round_trip(unicode_str), unicode_str)
assert_equal(round_trip(binary_bytes), binary_bytes)
assert type(round_trip(b'hello')) is bytes
assert type(round_trip(u'hello')) is unicode
assert_equal(round_trip(b''), b'')
assert_equal(round_trip(u''), u'')
assert round_trip(None) is None
compound = [utf8_bytes, None, binary_bytes, (None, unicode_str),
dict(utf8=utf8_bytes, chars=unicode_str, data=binary_bytes)
]
assert round_trip(compound) == tuple(compound)
def test_xml_wrap():
"""
Test the `ipalib.rpc.xml_wrap` function.
"""
f = rpc.xml_wrap
assert f([], API_VERSION) == tuple()
assert f({}, API_VERSION) == dict()
b = f(b'hello', API_VERSION)
assert isinstance(b, Binary)
# "Binary" is not "dict" or "tuple". pylint: disable=no-member
assert b.data == b'hello'
u = f(u'hello', API_VERSION)
assert type(u) is unicode
assert u == u'hello'
f([dict(one=False, two=u'hello'), None, b'hello'], API_VERSION)
def test_xml_unwrap():
"""
Test the `ipalib.rpc.xml_unwrap` function.
"""
f = rpc.xml_unwrap
assert f([]) == tuple()
assert f({}) == dict()
value = f(Binary(utf8_bytes))
assert type(value) is bytes
assert value == utf8_bytes
assert f(utf8_bytes) == unicode_str
assert f(unicode_str) == unicode_str
value = f([True, Binary(b'hello'), dict(one=1, two=utf8_bytes, three=None)])
assert value == (True, b'hello', dict(one=1, two=unicode_str, three=None))
assert type(value[1]) is bytes
assert type(value[2]['two']) is unicode
def test_xml_dumps():
"""
Test the `ipalib.rpc.xml_dumps` function.
"""
f = rpc.xml_dumps
params = (binary_bytes, utf8_bytes, unicode_str, None)
# Test serializing an RPC request:
data = f(params, API_VERSION, 'the_method')
(p, m) = loads(data)
assert_equal(m, u'the_method')
assert type(p) is tuple
assert rpc.xml_unwrap(p) == params
# Test serializing an RPC response:
data = f((params,), API_VERSION, methodresponse=True)
(tup, m) = loads(data)
assert m is None
assert len(tup) == 1
assert type(tup) is tuple
assert rpc.xml_unwrap(tup[0]) == params
# Test serializing an RPC response containing a Fault:
fault = Fault(69, unicode_str)
data = f(fault, API_VERSION, methodresponse=True)
e = raises(Fault, loads, data)
assert e.faultCode == 69
assert_equal(e.faultString, unicode_str)
def test_xml_loads():
"""
Test the `ipalib.rpc.xml_loads` function.
"""
f = rpc.xml_loads
params = (binary_bytes, utf8_bytes, unicode_str, None)
wrapped = rpc.xml_wrap(params, API_VERSION)
# Test un-serializing an RPC request:
data = dumps(wrapped, 'the_method', allow_none=True)
(p, m) = f(data)
assert_equal(m, u'the_method')
assert_equal(p, params)
# Test un-serializing an RPC response:
data = dumps((wrapped,), methodresponse=True, allow_none=True)
(tup, m) = f(data)
assert m is None
assert len(tup) == 1
assert type(tup) is tuple
assert_equal(tup[0], params)
# Test un-serializing an RPC response containing a Fault:
for error in (unicode_str, u'hello'):
fault = Fault(69, error)
data = dumps(fault, methodresponse=True, allow_none=True, encoding='UTF-8')
e = raises(Fault, f, data)
assert e.faultCode == 69
assert_equal(e.faultString, error)
assert type(e.faultString) is unicode
class test_xmlclient(PluginTester):
"""
Test the `ipalib.rpc.xmlclient` plugin.
"""
_plugin = rpc.xmlclient
def test_forward(self):
"""
Test the `ipalib.rpc.xmlclient.forward` method.
"""
class user_add(Command):
pass
o, _api, _home = self.instance('Backend', user_add, in_server=False)
args = (binary_bytes, utf8_bytes, unicode_str)
kw = dict(one=binary_bytes, two=utf8_bytes, three=unicode_str)
params = [args, kw]
result = (unicode_str, binary_bytes, utf8_bytes)
conn = DummyClass(
(
'user_add',
rpc.xml_wrap(params, API_VERSION),
{},
rpc.xml_wrap(result, API_VERSION),
),
(
'user_add',
rpc.xml_wrap(params, API_VERSION),
{},
Fault(3007, u"'four' is required"), # RequirementError
),
(
'user_add',
rpc.xml_wrap(params, API_VERSION),
{},
Fault(700, u'no such error'), # There is no error 700
),
)
# Create connection for the current thread
setattr(context, o.id, Connection(conn, lambda: None))
context.xmlclient = Connection(conn, lambda: None)
# Test with a successful return value:
assert o.forward('user_add', *args, **kw) == result
# Test with an errno the client knows:
e = raises(errors.RequirementError, o.forward, 'user_add', *args, **kw)
assert_equal(e.args[0], u"'four' is required")
# Test with an errno the client doesn't know
e = raises(errors.UnknownError, o.forward, 'user_add', *args, **kw)
assert_equal(e.code, 700)
assert_equal(e.error, u'no such error')
assert context.xmlclient.conn._calledall() is True
@pytest.mark.skip_ipaclient_unittest
@pytest.mark.needs_ipaapi
class test_xml_introspection(object):
@classmethod
def setup_class(cls):
try:
api.Backend.xmlclient.connect()
except (errors.NetworkError, IOError):
raise nose.SkipTest('%r: Server not available: %r' %
(__name__, api.env.xmlrpc_uri))
@classmethod
def teardown_class(cls):
request.destroy_context()
def test_list_methods(self):
result = api.Backend.xmlclient.conn.system.listMethods()
assert len(result)
assert 'ping' in result
assert 'user_add' in result
assert 'system.listMethods' in result
assert 'system.methodSignature' in result
assert 'system.methodHelp' in result
def test_list_methods_many_params(self):
try:
api.Backend.xmlclient.conn.system.listMethods('foo')
except Fault as f:
print(f)
assert f.faultCode == 3003
assert f.faultString == (
"command 'system.listMethods' takes no arguments")
else:
raise AssertionError('did not raise')
def test_ping_signature(self):
result = api.Backend.xmlclient.conn.system.methodSignature('ping')
assert result == [['struct', 'array', 'struct']]
def test_ping_help(self):
result = api.Backend.xmlclient.conn.system.methodHelp('ping')
assert result == 'Ping a remote server.'
def test_signature_no_params(self):
try:
api.Backend.xmlclient.conn.system.methodSignature()
except Fault as f:
print(f)
assert f.faultCode == 3007
assert f.faultString == "'method name' is required"
else:
raise AssertionError('did not raise')
def test_signature_many_params(self):
try:
api.Backend.xmlclient.conn.system.methodSignature('a', 'b')
except Fault as f:
print(f)
assert f.faultCode == 3004
assert f.faultString == (
"command 'system.methodSignature' takes at most 1 argument")
else:
raise AssertionError('did not raise')
def test_help_no_params(self):
try:
api.Backend.xmlclient.conn.system.methodHelp()
except Fault as f:
print(f)
assert f.faultCode == 3007
assert f.faultString == "'method name' is required"
else:
raise AssertionError('did not raise')
def test_help_many_params(self):
try:
api.Backend.xmlclient.conn.system.methodHelp('a', 'b')
except Fault as f:
print(f)
assert f.faultCode == 3004
assert f.faultString == (
"command 'system.methodHelp' takes at most 1 argument")
else:
raise AssertionError('did not raise')
@pytest.mark.skip_ipaclient_unittest
@pytest.mark.needs_ipaapi
class test_rpcclient_context(PluginTester):
"""
Test the context in `ipalib.rpc.rpcclient` plugin.
"""
def setup(self):
try:
api.Backend.rpcclient.connect(ca_certfile='foo')
except (errors.NetworkError, IOError):
raise nose.SkipTest('%r: Server not available: %r' %
(__name__, api.env.xmlrpc_uri))
def teardown(self):
if api.Backend.rpcclient.isconnected():
api.Backend.rpcclient.disconnect()
def test_context_cafile(self):
"""
Test that ca_certfile is set in `ipalib.rpc.rpcclient.connect`
"""
ca_certfile = getattr(context, 'ca_certfile', None)
assert_equal(ca_certfile, 'foo')
def test_context_principal(self):
"""
Test that principal is set in `ipalib.rpc.rpcclient.connect`
"""
principal = getattr(context, 'principal', None)
assert_equal(principal, 'admin@%s' % api.env.realm)
def test_context_request_url(self):
"""
Test that request_url is set in `ipalib.rpc.rpcclient.connect`
"""
request_url = getattr(context, 'request_url', None)
assert_equal(request_url, 'https://%s/ipa/session/json' % api.env.host)
def test_context_session_cookie(self):
"""
Test that session_cookie is set in `ipalib.rpc.rpcclient.connect`
"""
fuzzy_cookie = Fuzzy('^ipa_session=MagBearerToken=[A-Za-z0-9+\/]+=*;$')
session_cookie = getattr(context, 'session_cookie', None)
# pylint-2 is incorrectly spewing Too many positional arguments
# pylint: disable=E1121
unquoted = urllib.parse.unquote(session_cookie)
assert(unquoted == fuzzy_cookie)

View File

@@ -0,0 +1,408 @@
# Authors:
# Jason Gerard DeRose <jderose@redhat.com>
#
# Copyright (C) 2009 Red Hat
# see file 'COPYING' for use and warranty contextrmation
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Test the `ipalib.text` module.
"""
from __future__ import print_function
import os
import shutil
import tempfile
import nose
import six
import pytest
from ipatests.i18n import create_po, po_file_iterate
from ipalib.request import context
from ipalib import text
if six.PY3:
unicode = str
pytestmark = pytest.mark.tier0
singular = '%(count)d goose makes a %(dish)s'
plural = '%(count)d geese make a %(dish)s'
def test_create_translation():
f = text.create_translation
key = ('foo', None)
t = f(key)
assert context.__dict__[key] is t
class test_TestLang(object):
lang_env_vars = {'LC_ALL', 'LC_MESSAGES', 'LANGUAGE', 'LANG'}
def setup_lang(self):
"""
Set all env variables used by gettext to localize translation files
to xh_ZA
"""
self.lang = 'xh_ZA'
self.saved_locale = {
k: v for k, v in os.environ.items() if k in self.lang_env_vars}
os.environ.update(
{env_var: self.lang for env_var in self.lang_env_vars}
)
def teardown_lang(self):
"""
Revert the locale settings to original values. If the original env
variable was not set before, it will be popped off os.environ
"""
for env_var in self.lang_env_vars:
if env_var not in self.saved_locale:
os.environ.pop(env_var, None)
os.environ.update(self.saved_locale)
def setup(self):
self.tmp_dir = None
self.setup_lang()
self.domain = 'ipa'
self.pot_basename = '%s.pot' % self.domain
self.po_basename = '%s.po' % self.lang
self.mo_basename = '%s.mo' % self.domain
self.tmp_dir = tempfile.mkdtemp()
self.locale_dir = os.path.join(self.tmp_dir, 'test_locale')
self.msg_dir = os.path.join(self.locale_dir, self.lang, 'LC_MESSAGES')
if not os.path.exists(self.msg_dir):
os.makedirs(self.msg_dir)
self.pot_file = os.path.join(
os.path.dirname(__file__), 'data', self.pot_basename)
self.mo_file = os.path.join(self.msg_dir, self.mo_basename)
self.po_file = os.path.join(self.tmp_dir, self.po_basename)
result = create_po(self.pot_file, self.po_file, self.mo_file)
if result:
raise nose.SkipTest('Unable to create po file "%s" & mo file "%s" from pot file "%s"' %
(self.po_file, self.mo_file, self.pot_file))
if not os.path.isfile(self.po_file):
raise nose.SkipTest(
'Test po file unavailable: {}'.format(self.po_file))
if not os.path.isfile(self.mo_file):
raise nose.SkipTest(
'Test mo file unavailable: {}'.format(self.mo_file))
self.po_file_iterate = po_file_iterate
def teardown(self):
self.teardown_lang()
if self.tmp_dir is not None:
shutil.rmtree(self.tmp_dir)
def test_test_lang(self):
print("test_test_lang")
# The test installs the test message catalog under the xh_ZA
# (e.g. Zambia Xhosa) language by default. It would be nice to
# use a dummy language not associated with any real language,
# but the setlocale function demands the locale be a valid
# known locale, Zambia Xhosa is a reasonable choice :)
# Create a gettext translation object specifying our domain as
# 'ipa' and the locale_dir as 'test_locale' (i.e. where to
# look for the message catalog). Then use that translation
# object to obtain the translation functions.
def get_msgstr(msg):
gt = text.GettextFactory(localedir=self.locale_dir)(msg)
return unicode(gt)
def get_msgstr_plural(singular, plural, count):
ng = text.NGettextFactory(localedir=self.locale_dir)(singular, plural, count)
return ng(count)
result = self.po_file_iterate(self.po_file, get_msgstr, get_msgstr_plural)
assert result == 0
class test_LazyText(object):
klass = text.LazyText
def test_init(self):
inst = self.klass('foo', 'bar')
assert inst.domain == 'foo'
assert inst.localedir == 'bar'
assert inst.key == ('foo', 'bar')
class test_FixMe(object):
klass = text.FixMe
def test_init(self):
inst = self.klass('user.label')
assert inst.msg == 'user.label'
assert inst.domain is None
assert inst.localedir is None
def test_repr(self):
inst = self.klass('user.label')
assert repr(inst) == "FixMe('user.label')"
def test_unicode(self):
inst = self.klass('user.label')
assert unicode(inst) == u'<user.label>'
assert type(unicode(inst)) is unicode
class test_Gettext(object):
klass = text.Gettext
def test_init(self):
inst = self.klass('what up?', 'foo', 'bar')
assert inst.domain == 'foo'
assert inst.localedir == 'bar'
assert inst.msg is 'what up?'
assert inst.args == ('what up?', 'foo', 'bar')
def test_repr(self):
inst = self.klass('foo', 'bar', 'baz')
assert repr(inst) == "Gettext('foo', domain='bar', localedir='baz')"
def test_unicode(self):
inst = self.klass('what up?', 'foo', 'bar')
assert unicode(inst) == u'what up?'
def test_mod(self):
inst = self.klass('hello %(adj)s nurse', 'foo', 'bar')
assert inst % dict(adj='naughty', stuff='junk') == 'hello naughty nurse'
def test_eq(self):
inst1 = self.klass('what up?', 'foo', 'bar')
inst2 = self.klass('what up?', 'foo', 'bar')
inst3 = self.klass('Hello world', 'foo', 'bar')
inst4 = self.klass('what up?', 'foo', 'baz')
assert (inst1 == inst1) is True
assert (inst1 == inst2) is True
assert (inst1 == inst3) is False
assert (inst1 == inst4) is False
# Test with args flipped
assert (inst2 == inst1) is True
assert (inst3 == inst1) is False
assert (inst4 == inst1) is False
def test_ne(self):
inst1 = self.klass('what up?', 'foo', 'bar')
inst2 = self.klass('what up?', 'foo', 'bar')
inst3 = self.klass('Hello world', 'foo', 'bar')
inst4 = self.klass('what up?', 'foo', 'baz')
assert (inst1 != inst2) is False
assert (inst1 != inst2) is False
assert (inst1 != inst3) is True
assert (inst1 != inst4) is True
# Test with args flipped
assert (inst2 != inst1) is False
assert (inst3 != inst1) is True
assert (inst4 != inst1) is True
class test_NGettext(object):
klass = text.NGettext
def test_init(self):
inst = self.klass(singular, plural, 'foo', 'bar')
assert inst.singular is singular
assert inst.plural is plural
assert inst.domain == 'foo'
assert inst.localedir == 'bar'
assert inst.args == (singular, plural, 'foo', 'bar')
def test_repr(self):
inst = self.klass('sig', 'plu', 'foo', 'bar')
assert repr(inst) == \
"NGettext('sig', 'plu', domain='foo', localedir='bar')"
def test_call(self):
inst = self.klass(singular, plural, 'foo', 'bar')
assert inst(0) == plural
assert inst(1) == singular
assert inst(2) == plural
assert inst(3) == plural
def test_mod(self):
inst = self.klass(singular, plural, 'foo', 'bar')
assert inst % dict(count=0, dish='frown') == '0 geese make a frown'
assert inst % dict(count=1, dish='stew') == '1 goose makes a stew'
assert inst % dict(count=2, dish='pie') == '2 geese make a pie'
def test_eq(self):
inst1 = self.klass(singular, plural, 'foo', 'bar')
inst2 = self.klass(singular, plural, 'foo', 'bar')
inst3 = self.klass(singular, '%(count)d thingies', 'foo', 'bar')
inst4 = self.klass(singular, plural, 'foo', 'baz')
assert (inst1 == inst1) is True
assert (inst1 == inst2) is True
assert (inst1 == inst3) is False
assert (inst1 == inst4) is False
# Test with args flipped
assert (inst2 == inst1) is True
assert (inst3 == inst1) is False
assert (inst4 == inst1) is False
def test_ne(self):
inst1 = self.klass(singular, plural, 'foo', 'bar')
inst2 = self.klass(singular, plural, 'foo', 'bar')
inst3 = self.klass(singular, '%(count)d thingies', 'foo', 'bar')
inst4 = self.klass(singular, plural, 'foo', 'baz')
assert (inst1 != inst2) is False
assert (inst1 != inst2) is False
assert (inst1 != inst3) is True
assert (inst1 != inst4) is True
# Test with args flipped
assert (inst2 != inst1) is False
assert (inst3 != inst1) is True
assert (inst4 != inst1) is True
class test_GettextFactory(object):
klass = text.GettextFactory
def test_init(self):
# Test with defaults:
inst = self.klass()
assert inst.domain == 'ipa'
assert inst.localedir is None
# Test with overrides:
inst = self.klass('foo', 'bar')
assert inst.domain == 'foo'
assert inst.localedir == 'bar'
def test_repr(self):
# Test with defaults:
inst = self.klass()
assert repr(inst) == "GettextFactory(domain='ipa', localedir=None)"
# Test with overrides:
inst = self.klass('foo', 'bar')
assert repr(inst) == "GettextFactory(domain='foo', localedir='bar')"
def test_call(self):
inst = self.klass('foo', 'bar')
g = inst('what up?')
assert type(g) is text.Gettext
assert g.msg is 'what up?'
assert g.domain == 'foo'
assert g.localedir == 'bar'
class test_NGettextFactory(object):
klass = text.NGettextFactory
def test_init(self):
# Test with defaults:
inst = self.klass()
assert inst.domain == 'ipa'
assert inst.localedir is None
# Test with overrides:
inst = self.klass('foo', 'bar')
assert inst.domain == 'foo'
assert inst.localedir == 'bar'
def test_repr(self):
# Test with defaults:
inst = self.klass()
assert repr(inst) == "NGettextFactory(domain='ipa', localedir=None)"
# Test with overrides:
inst = self.klass('foo', 'bar')
assert repr(inst) == "NGettextFactory(domain='foo', localedir='bar')"
def test_call(self):
inst = self.klass('foo', 'bar')
ng = inst(singular, plural, 7)
assert type(ng) is text.NGettext
assert ng.singular is singular
assert ng.plural is plural
assert ng.domain == 'foo'
assert ng.localedir == 'bar'
class test_ConcatenatedText(object):
klass = text.ConcatenatedLazyText
def test_init(self):
lst = ['a', 'b', 'c', 3]
inst = self.klass(*lst)
assert inst.components == lst
assert unicode(inst) == 'abc3'
def test_repr(self):
lazytext = text.Gettext('foo', 'bar', 'baz')
inst = self.klass(lazytext)
assert repr(inst) == "ConcatenatedLazyText([%r])" % lazytext
def test_unicode(self):
inst = self.klass('[', text.Gettext('green', 'foo', 'bar'), 1, ']')
assert unicode(inst) == u'[green1]'
def test_mod(self):
inst = self.klass('[', text.Gettext('%(color)s', 'foo', 'bar'), ']')
assert inst % dict(color='red', stuff='junk') == '[red]'
def test_add(self):
inst = (text.Gettext('pale ', 'foo', 'bar') +
text.Gettext('blue', 'foo', 'bar'))
assert unicode(inst) == 'pale blue'
inst = (text.Gettext('bright ', 'foo', 'bar') +
text.Gettext('pale ', 'foo', 'bar') +
text.Gettext('blue', 'foo', 'bar'))
assert unicode(inst) == 'bright pale blue'
inst = text.Gettext('yellow', 'foo', 'bar') + '!'
assert unicode(inst) == 'yellow!'
inst = '!' + text.Gettext('yellow', 'foo', 'bar')
assert unicode(inst) == '!yellow'
inst = '!' + ('!' + text.Gettext('yellow', 'foo', 'bar'))
assert unicode(inst) == '!!yellow'
inst = (text.Gettext('yellow', 'foo', 'bar') + '!') + '!'
assert unicode(inst) == 'yellow!!'

View File

@@ -0,0 +1,153 @@
# Authors:
# Rob Crittenden <rcritten@redhat.com>
#
# Copyright (C) 2010 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Test the `ipalib.x509` module.
"""
import base64
import datetime
import pytest
from ipalib import x509
from ipapython.dn import DN
pytestmark = pytest.mark.tier0
# certutil -
# certificate for CN=ipa.example.com,O=IPA
goodcert = (
b'MIICAjCCAWugAwIBAgICBEUwDQYJKoZIhvcNAQEFBQAwKTEnMCUGA1UEAxMeSVBB'
b'IFRlc3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTEwMDYyNTEzMDA0MloXDTE1'
b'MDYyNTEzMDA0MlowKDEMMAoGA1UEChMDSVBBMRgwFgYDVQQDEw9pcGEuZXhhbXBs'
b'ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJcZ+H6+cQaN/BlzR8OY'
b'kVeJgaU5tCaV9FF1m7Ws/ftPtTJUaSL1ncp6603rjA4tH1aa/B8i8xdC46+ZbY2a'
b'u8b9ryGcOsx2uaRpNLEQ2Fy//q1kQC8oM+iD8Nd6osF0a2wnugsgnJHPuJzhViaW'
b'xYgzk5DRdP81debokF3f3FX/AgMBAAGjOjA4MBEGCWCGSAGG+EIBAQQEAwIGQDAT'
b'BgNVHSUEDDAKBggrBgEFBQcDATAOBgNVHQ8BAf8EBAMCBPAwDQYJKoZIhvcNAQEF'
b'BQADgYEALD6X9V9w381AzzQPcHsjIjiX3B/AF9RCGocKZUDXkdDhsD9NZ3PLPEf1'
b'AMjkraKG963HPB8scyiBbbSuSh6m7TCp0eDgRpo77zNuvd3U4Qpm0Qk+KEjtHQDj'
b'NNG6N4ZnCQPmjFPScElvc/GgW7XMbywJy2euF+3/Uip8cnPgSH4='
)
goodcert_headers = (
b'-----BEGIN CERTIFICATE-----\n' +
goodcert +
b'\n-----END CERTIFICATE-----'
)
# The base64-encoded string 'bad cert'
badcert = (
b'-----BEGIN CERTIFICATE-----\n'
b'YmFkIGNlcnQ=\r\n'
b'-----END CERTIFICATE-----'
)
good_pkcs7 = (
b'-----BEGIN PKCS7-----\n'
b'MIIDvAYJKoZIhvcNAQcCoIIDrTCCA6kCAQExADALBgkqhkiG9w0BBwGgggOPMIID\n'
b'izCCAnOgAwIBAgIBATANBgkqhkiG9w0BAQsFADA2MRQwEgYDVQQKDAtFWEFNUExF\n'
b'LkNPTTEeMBwGA1UEAwwVQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTE3MDkyMDIw\n'
b'NDI1N1oXDTM3MDkyMDIwNDI1N1owNjEUMBIGA1UECgwLRVhBTVBMRS5DT00xHjAc\n'
b'BgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQAD\n'
b'ggEPADCCAQoCggEBAMNojX57UCCPTtEn9tQJBS4By5NixwodKm1UqOGsiecDrB0i\n'
b'Pw7D6uGP6g4b6srYtbh+YsRJnfekB2L08q1dX3LVEItq2TS0WKqgZuRZkw7DvnGl\n'
b'eANMwjHmE8k6/E0yI3GGxJLAfDZYw6CDspLkyN9anjQwVCz5N5z5bpeqi5BeVwin\n'
b'O8WVF6FNn3iyL66uwOsTGEzCo3Y5HiwqYgaND73TtdsBHcIqOdRql3CC3IdoXXcW\n'
b'044w4Lm2E95MuY729pPBHREtyzVkYtyuoKJ8KApghIY5oCklBkRDjyFK4tE7iF/h\n'
b's+valeT9vcz2bHMIpvbjqAu/kqE8MjcNEFPjLhcCAwEAAaOBozCBoDAfBgNVHSME\n'
b'GDAWgBTUB04/d1eLhbMtBi4AB65tsAt+2TAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud\n'
b'DwEB/wQEAwIBxjAdBgNVHQ4EFgQU1AdOP3dXi4WzLQYuAAeubbALftkwPQYIKwYB\n'
b'BQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vaXBhLWNhLmdyZXlvYWsuY29t\n'
b'L2NhL29jc3AwDQYJKoZIhvcNAQELBQADggEBADQFwX1uh8tqLq8SqWZWtH95j33o\n'
b'5Ze2dW7sVppb/wVnNauG0wDQW7uIx+Ynr7GgufXLNBMn1aP/mA2CdHk7NZz2IB1s\n'
b'ZvbIfE8dVxzkA+Hh9d6cdgk4eU5rGf6Fw8ScEJ/48Mmncea3uGkHcOmt+BGLA8a1\n'
b'wtruy+iQylOkbv36CbxKV7IsZDP106Zc+cVeOUQZnCLKmvQkotn6UJd8N1X0R2J3\n'
b'4/qv0rUtcCnyEBNSgpTGCRlYM4kd98Dqc5W7wUpMcsQMFxQMSYY7pFQkdLPfJEx2\n'
b'Mg63SPawxfAgUeukrdsF3wTIKkIBu1TVse+kvRvgmRRrfF2a4ZOv5qORe2uhADEA\n'
b'-----END PKCS7-----'
)
class test_x509(object):
"""
Test `ipalib.x509`
I created the contents of this certificate with a self-signed CA with:
% certutil -R -s "CN=ipa.example.com,O=IPA" -d . -a -o example.csr
% ./ipa host-add ipa.example.com
% ./ipa cert-request --add --principal=test/ipa.example.com example.csr
"""
def test_1_load_base64_cert(self):
"""
Test loading a base64-encoded certificate.
"""
# Load a good cert
x509.load_pem_x509_certificate(goodcert_headers)
# Load a good cert with headers and leading text
newcert = (
b'leading text\n' + goodcert_headers)
x509.load_pem_x509_certificate(newcert)
# Load a good cert with bad headers
newcert = b'-----BEGIN CERTIFICATE-----' + goodcert_headers
with pytest.raises((TypeError, ValueError)):
x509.load_pem_x509_certificate(newcert)
# Load a bad cert
with pytest.raises(ValueError):
x509.load_pem_x509_certificate(badcert)
def test_1_load_der_cert(self):
"""
Test loading a DER certificate.
"""
der = base64.b64decode(goodcert)
# Load a good cert
x509.load_der_x509_certificate(der)
def test_3_cert_contents(self):
"""
Test the contents of a certificate
"""
# Verify certificate contents. This exercises python-cryptography
# more than anything but confirms our usage of it.
not_before = datetime.datetime(2010, 6, 25, 13, 0, 42)
not_after = datetime.datetime(2015, 6, 25, 13, 0, 42)
cert = x509.load_pem_x509_certificate(goodcert_headers)
assert DN(cert.subject) == DN(('CN', 'ipa.example.com'), ('O', 'IPA'))
assert DN(cert.issuer) == DN(('CN', 'IPA Test Certificate Authority'))
assert cert.serial_number == 1093
assert cert.not_valid_before == not_before
assert cert.not_valid_after == not_after
def test_load_pkcs7_pem(self):
certlist = x509.pkcs7_to_certs(good_pkcs7, datatype=x509.PEM)
assert len(certlist) == 1
cert = certlist[0]
assert DN(cert.subject) == DN('CN=Certificate Authority,O=EXAMPLE.COM')
assert cert.serial_number == 1