Imported Upstream version 4.6.2
This commit is contained in:
22
ipatests/test_ipalib/__init__.py
Normal file
22
ipatests/test_ipalib/__init__.py
Normal 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.
|
||||
"""
|
||||
47
ipatests/test_ipalib/data/ipa.pot
Normal file
47
ipatests/test_ipalib/data/ipa.pot
Normal 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] ""
|
||||
164
ipatests/test_ipalib/test_aci.py
Normal file
164
ipatests/test_ipalib/test_aci.py
Normal 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";)')
|
||||
286
ipatests/test_ipalib/test_backend.py
Normal file
286
ipatests/test_ipalib/test_backend.py
Normal 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)
|
||||
375
ipatests/test_ipalib/test_base.py
Normal file
375
ipatests/test_ipalib/test_base.py
Normal 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
|
||||
36
ipatests/test_ipalib/test_capabilities.py
Normal file
36
ipatests/test_ipalib/test_capabilities.py
Normal 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')
|
||||
120
ipatests/test_ipalib/test_cli.py
Normal file
120
ipatests/test_ipalib/test_cli.py
Normal 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
|
||||
"""
|
||||
610
ipatests/test_ipalib/test_config.py
Normal file
610
ipatests/test_ipalib/test_config.py
Normal 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
|
||||
244
ipatests/test_ipalib/test_crud.py
Normal file
244
ipatests/test_ipalib/test_crud.py
Normal 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')
|
||||
377
ipatests/test_ipalib/test_errors.py
Normal file
377
ipatests/test_ipalib/test_errors.py
Normal 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)
|
||||
1170
ipatests/test_ipalib/test_frontend.py
Normal file
1170
ipatests/test_ipalib/test_frontend.py
Normal file
File diff suppressed because it is too large
Load Diff
95
ipatests/test_ipalib/test_messages.py
Normal file
95
ipatests/test_ipalib/test_messages.py
Normal 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'},
|
||||
)
|
||||
]}
|
||||
96
ipatests/test_ipalib/test_output.py
Normal file
96
ipatests/test_ipalib/test_output.py
Normal 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
|
||||
)
|
||||
1753
ipatests/test_ipalib/test_parameters.py
Normal file
1753
ipatests/test_ipalib/test_parameters.py
Normal file
File diff suppressed because it is too large
Load Diff
309
ipatests/test_ipalib/test_plugable.py
Normal file
309
ipatests/test_ipalib/test_plugable.py
Normal 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')
|
||||
397
ipatests/test_ipalib/test_rpc.py
Normal file
397
ipatests/test_ipalib/test_rpc.py
Normal 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)
|
||||
408
ipatests/test_ipalib/test_text.py
Normal file
408
ipatests/test_ipalib/test_text.py
Normal 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!!'
|
||||
153
ipatests/test_ipalib/test_x509.py
Normal file
153
ipatests/test_ipalib/test_x509.py
Normal 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
|
||||
Reference in New Issue
Block a user