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

Jakub Hrozek jhrozek at redhat.com
Tue Mar 5 16:31:09 UTC 2013


On Fri, Mar 01, 2013 at 01:39:22PM +0100, Pavel Březina wrote:
> 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.
> 

OK, the files are hopefully better split now:

There is common_dom.c for tests that would like some common way to
connect to a test sysdb. In future, we should convert even the existing
tests like sysdb-test or sysdb-ssh-test to use this common code to avoid
code duplication. I will file a ticket about this.

Then there is common_tev.c for tests that require an event loop and
may need to issue dummy tevent requests. 

Both files are stored in the src/tests. I think we should shuffle the
files a bit so that only helpers that do not require neither check nor
cmocka would be in the src/tests subdirectory directly. The check-based
tests and their specific utils should be moved to src/tests/check. This
would be another ticket.

> 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
> 

Currently there are no mock-related functions that would be reusable by
any test (one that would test provider and one that would test responder
for example). 

The functions you mentioned above were moved to
src/tests/cmocka/cmocka_common_resp.c as they would be reused by any
cmocka-based test that tests the NSS responder.

> Why did you include setjmp.h?

For clarity the setjmp and other required headers are now included in
header src/tests/cmocka/common_mock.h



More information about the sssd-devel mailing list