On 04/21/2015 05:08 PM, Nikolai Kondrashov wrote:
On 04/21/2015 04:59 PM, Michal Židek wrote:
> On 04/21/2015 03:32 PM, Nikolai Kondrashov wrote:
>> On 04/21/2015 04:23 PM, Michal Židek wrote:
>>> On 04/20/2015 07:15 PM, Nikolai Kondrashov wrote:
>>>> On 03/19/2015 07:27 PM, Michal Židek wrote:
>>>>> On 03/18/2015 03:48 PM, Nikolai Kondrashov wrote:
>>>>>> On 03/18/2015 03:06 AM, Michal Židek wrote:
>>>>>
>>>>> I see. You mean to test results from getpwall.
>>>>> We could do this:
>>>>> Create simple asserts like
>>>>> assert_get_user_by_uid and
>>>>> assert_get_user_by_name
>>>>> as described in my previous mail bellow. Than
>>>>> create their getpwall ekvivalents like
>>>>> assert_getpwall_uid
>>>>> assert_getpwall_name
>>>>>
>>>>> These functions would have the same arguments as
>>>>> the simpler asserts (not just one time, but as
>>>>> a list).
>>>>> In these functions we would first convert the list
>>>>> returned by getpwall to a dictionary where the
>>>>> uid (name) will be a key and the pwd structure a
>>>>> value. Then we would iterate throught the list
>>>>> of input values and for each UID (name) we
>>>>> would check if the expected value is matching the
>>>>> pwd structure (in the same way as the simple
>>>>> asserts will do, so the matching part will be
>>>>> reusable). The usage would be like this:
>>>>>
>>>>> uid_expval_list = [(2001, {"name"="user1"}),
>>>>> (2002, {"name"="user2"})]
>>>>>
>>>>> assert_getpwall_uid(ldap_conn, uid_expval_list)
>>>>>
>>>>> Similiar would it be with the assert_getpwall_name.
>>>>> Of course we could check for more than just correct
>>>>> "name" attribute, but checking just the "name"
attribute
>>>>> should be possible (we would only test requested
>>>>> parts of pwd structure). As you see, we do not
>>>>> need to filter any root user if we do it this way
>>>>> (yes the root will be there in the returned list
>>>>> by getpwall but only names in the uid_expval_list
>>>>> will be used).
>>>>>
>>>>> Anyway, I am OK if the getpwall part is done later
>>>>> and for now only the simple asserts are implemented
>>>>> and used in the sanity tests.
>>>>
>>>> This looks almost perfectly fine, but it accounts only for checking
>>>> users that
>>>> should be there, yet not for users that *shouldn't* be there. So, I
>>>> think it
>>>> is still better to explicitly remove that one root account and maybe
>>>> have
>>>> variations of assert_getpwall* which check for the absence of extra
>>>> users.
>>>>
>>>
>>> I am not sure if this is good. getpwall can return a lot of
>>> users we do not care about (root, ldap, ntp, abrt, etc.).
>>> IMO we should simply ignore them and do not mention them
>>> in any way in the code. I do not think the API provides
>>> a way to ask for sssd managed users only, like in
>>> getent -s sss passwd (correct me if I am wrong). I f there was
>>> such option, then that would be what we would do, but if there
>>> is not, I think ignoring the users is OK.
>>
>> Yes, that would be true, if we were using the host's passwd and group
>> databases, but we're not. We're using nss_wrapper with our own dummy
passwd
>> and group files, generated in src/tests/intg/Makefile.am and containing
>> only
>> "root" entries.
>>
>> I did that specifically to avoid clashes with host databases.
>>
>> Nick
>
> That is true, I did not realize that. In that case removing
> the root is OK. Just make sure you remove the one big assert
> and replace it with smaller ones that check one particular
> thing (as I described in some previous mail).
Sure, I'm working on that at the moment. Will send updates.
Alright, I did an assertions module by mutating the old "ent" module.
Please find it attached.
It has both separate, small asserts for verifying individual entries,
dictionary-based asserts for verifying a few entries from getpwent, and big
asserts for verifying the whole database as I do in initial tests.
In short, I tried to address all your requests. Although, not exactly in the
way you suggested, but making some shortcuts, trying to keep the code smaller.
Here are some examples of using the module:
# Assert getpwnam("user1") returns an entry with uid == 1001 and
# gid == 2001
ent.passwd_assert_by_name("user1", dict(uid=1001, gid=2001))
# Assert one of the entries returned by getgrent(), with name "group1",
# has gid == 2001 and no members, and another entry, with name
# "one_user_group2", has gid == 2016 and one member named
"user2"
ent.group_name_dict_assert(dict(group1 = dict(gid=2001, mem=[]),
one_user_group2 = dict(gid=2016,
mem=["user2"])))
# Assert one of the entries returned by getpwent(), with uid == 1003,
# has name "user3", and another entry, with uid == 1002, has shell
# "/bin/bash"
ent.passwd_uid_dict_assert({1003: dict(name="user3"),
1002: dict(shell="/bin/bash")})
# Assert all the entries returned by getpwent() match at least one of the
# specified patterns and there are no other entries, entries returned by
# getpwnam() for names of each of those match, entries returned by
# getpwuid() for uids of each of those match.
ent.passwd_assert(
[
dict(name='user1', passwd='*', uid=1001, gid=2001,
gecos='1001', dir='/home/user1', shell='/bin/bash'),
dict(name='user2', passwd='*', uid=1002, gid=2002,
gecos='1002', dir='/home/user2', shell='/bin/bash'),
dict(name='user3', passwd='*', uid=1003, gid=2003,
gecos='1003', dir='/home/user3', shell='/bin/bash')
], list=True, name=True, uid=True)
# Assert all the entries returned by getpwent() match at least one of the
# specified patterns and there are no other entries.
ent.passwd_assert(
[
dict(shell='/bin/bash'),
dict(gid=2001, shell='/bin/bash'),
dict(dir='/home/user3', shell='/bin/bash')
], list=True)
I attempted to describe the logic behind the generic matching function "diff",
but please ask if anything is not clear. There is one particular flaw to it,
though: there is no way to match a list partially, e.g. to match for presence
of just a few group members, instead of all. I think we can employ tuples for
these. I.e. say that a tuple pattern matches a list if all tuple items match
at least one list item, but not necessarily the other way around.
The assert functions attempt to explain the differences in the assert message.
The explanations might not be perfect, but I think they help quite a bit.
I'll show some simpler cases as examples:
Code:
ent.passwd_assert_by_name("user1", dict(uid=1002, gid=2001))
Traceback (most recent call last):
File
"/home/nkondras/projects/fedorahosted.org/sssd/src/tests/intg/ldap_test.py",
line 272, in test_sanity_rfc2307_bis
ent.passwd_assert_by_name("user1", dict(uid=1002, gid=2001))
File
"/home/nkondras/projects/fedorahosted.org/sssd/src/tests/intg/ent.py", line 135,
in passwd_assert_by_name
assert not d, d
AssertionError: 'uid' mismatch: 1002 != 1001
Code:
ent.passwd_uid_dict_assert({1003: dict(name="user4"),
1002: dict(shell="/bin/bash")})
Traceback (most recent call last):
File
"/home/nkondras/projects/fedorahosted.org/sssd/src/tests/intg/ldap_test.py",
line 282, in test_sanity_rfc2307_bis
1002: dict(shell="/bin/bash")})
File
"/home/nkondras/projects/fedorahosted.org/sssd/src/tests/intg/ent.py", line 190,
in passwd_uid_dict_assert
assert not d, d
AssertionError: 1003 mismatch: 'name' mismatch: 'user4' !=
'user3'
And one complicated:
Code:
ent.passwd_assert(
[
dict(gid=2001, shell='/bin/sh'),
dict(dir='/home/user3', shell='/bin/bash')
], list=True)
Traceback (most recent call last):
File
"/home/nkondras/projects/fedorahosted.org/sssd/src/tests/intg/ldap_test.py",
line 276, in test_sanity_rfc2307_bis
], list=True)
File
"/home/nkondras/projects/fedorahosted.org/sssd/src/tests/intg/ent.py", line 243,
in passwd_assert
assert not d, d
AssertionError: list mismatch:
unmatched pattern item(s):
[{'gid': 2001, 'shell': '/bin/sh'}]
unmatched entry item(s):
[{'dir': '/home/user1',
'gecos': '1001',
'gid': 2001,
'name': 'user1',
'passwd': '*',
'shell': '/bin/bash',
'uid': 1001},
{'dir': '/home/user2',
'gecos': '1002',
'gid': 2002,
'name': 'user2',
'passwd': '*',
'shell': '/bin/bash',
'uid': 1002}]
Another note: assertion backtraces will always include the module's assertion
function itself, there doesn't seem to be an easy way to imitate assertion
failure at the invocation point. However, I kept all "assert" statements short
and simple, so they at least don't grab too much attention.
Nick