[SSSD] [PATCH] RFC: Unit test for the NSS responder based on the cmocka library

Pavel Březina pbrezina at redhat.com
Fri Mar 1 12:39:22 UTC 2013


On 02/12/2013 06:12 PM, Jakub Hrozek wrote:
> Hi,
>
> Short version - attached is a patch proposal for a unit test based on
> cmocka. The patches are an example of a complex, yet isolated unit test
> and I'd like to get opinions on whether this would be a good way to go.
>
> Long version:
> Our check based test suite is OK for developing simple tests for APIs
> like sysdb but not really great for testing of more complex interfaces.
>
> In particular, it's hard to simulate certain pieces of functionality
> that require interaction with network or the rest of the system such as
> LDAP searches or logins, especially in environments like buildsystems.
>
> I think we might want to look at Cmocka to provide this missing functionality
> and test complex interfaces in isolation. Cmocka[1] is a fork of Google's
> cmockery which is not maintained upstream anymore. Cmocka is maintained
> by Andreas Schneider.
>
> I've been playing with cmocka lately and wrote a couple of patches that
> add a unit test for the NSS responder, in particular the getpwnam()
> function. It was quite easy to simulate the Data Provider and the client
> using two concepts:
>
> 1) cmocka's mocking feature
> Functions that provide external interface, like the dummy DP functions
> in my patches, can access a stack of values. The unit test can push some
> expected return values onto the stack before launching the test and the
> dummy functions would then pop the values and use them as appropriate.
> It's quite easy to simulate a Data Provider saving an entry to cache
> with call like this (pseudocode):
>
> int unit_test()
> {
>      will_return(sss_dp_get_account_recv, "testuser");
>      will_return(sss_dp_get_account_recv, 10);
>      will_return(sss_dp_get_account_recv, 11);
> }
>
> int sss_dp_get_account_recv(TALLOC_CTX *mem_ctx, tevent_req *req)
> {
>      char *username = mock();
>      uid_t uid = mock();
>      gid_t gid = mock();
>
>      sysdb_store_user(username, uid, gid);
> }
>
> 2) the -wrap feature of ld
> It is possible to selectively override functions from modules linked against
> to intercept calls using the -wrap feature of ld. In my unit tests I used
> this feature to check results of responder search with defined callbacks
> instead of returning the results to the nss client. Here is a simple example
> of intercepting a call to negative cache to make sure the negative cache
> is hit when it's supposed to:
>
> int __wrap_sss_ncache_check_user(struct sss_nc_ctx *ctx, int ttl,
>                                   struct sss_domain_info *dom,
>                                   const char *name)
> {
>      int ret;
>
>      ret = __real_sss_ncache_check_user(ctx, ttl, dom, name);
>      if (ret == EEXIST) {
>          nss_test_ctx->ncache_hit = true;
>      }
>      return ret;
> }
>
> There's a couple of boilerplate functions but once these are in place,
> they can be reused to cover different pieces of functionality..the
> attached patches test the following requests:
>   * cached user including assertion that DP was not contacted
>   * nonexistant user including assertion that on a subsequent lookup, the
>     request is returned from negative cache
>   * search for a user that has not been cache prior to the search
>   * updating an expired user including assertions that the user had been
>     updated from DP and the updated entry is returned.
>
> The downsides of using cmocka as far as I can see are:
>    * writing the mocking code can be tedious. On the other hand, the NSS
>      responder I picked was probably the most complex code I could test
>      as it communicates with both DP and the client library. Even more
>      isolated testing (the AD sites feature comes to mind) would be much
>      easier I think.
>    * cmocka is not present in RHEL
>
> I'll be glad to hear comments about this unit test proposal. Patches
> are attached.
>
> [1] http://cmocka.cryptomilk.org/

Very nice.

I would like to increase granularity though. First of all we should
separate cmocka test files from check files on directory/filename
level. I'd say that all cmocka stuff should go into tests/cmocka. For
example, there are files common_check.c, common_dom.c, common.c, but
only common_dom.c is suitable for cmocka. When more common files and
tests comes, it will be hard to distinguish them.

Testing with cmocka is mainly about mocking structures and creating
wrappers around functions. We should try to create reusable mocks and
wrappers right from the beginning, making them independent on tests.
For example: mock_rctx(), mock_cctx(), sss_dp_get_account_send(),
sss_dp_get_account_recv(), ... I believe these and more functions can
be reused when testing other responders so they should be placed in
e.g. common_responder.c

Why did you include setjmp.h?




More information about the sssd-devel mailing list