Client Testing Framework

The testing framework of the C++ client library is based on CPPUnit. More...

Classes

class  ClientOutputter
class  ClientListener
class  TestFileSource
 This code uses the ClientTest and RawFileSyncSource to test real synchronization against a server. More...
class  RegisterTest
 the only purpose of this class is to own the first TestFileSource and to register its tests at program startup
class  CreateSource
 helper class to encapsulate ClientTest::Config::createsource_t pointer and the corresponding parameters More...
class  LocalTests
 local test of one sync source and utility functions also used by sync tests More...
class  SyncTests
 Tests synchronization with one or more sync sources enabled. More...
class  ClientTestFactory
 generates tests on demand based on what the client supports More...

Defines

#define SOURCE_ASSERT_NO_FAILURE(_source, _x)
 execute _x and then check the status of the _source pointer
#define SOURCE_ASSERT(_source, _x)
 check _x for true and then the status of the _source pointer
#define SOURCE_ASSERT_EQUAL(_source, _value, _x)
 check that _x evaluates to a specific value and then the status of the _source pointer
#define SOURCE_ASSERT_MESSAGE(_message, _source, _x)
 same as SOURCE_ASSERT() with a specific failure message
#define ADD_TEST(_class, _function)   addTest(new CppUnit::TestCaller<_class>(getName() + "::" #_function, &_class::_function, *this))
 convenience macro for adding a test name like a function, to be used inside an instance of that class

Functions

void simplifyFilename (string &filename)
const string & getCurrentTest ()
int main (int argc, char *argv[])
virtual void ClientTest::registerTests ()
 This is the only function provided by ClientTest itself: it registers tests using this instance of ClientTest for later use during a test run.
 ClientTest::ClientTest (int serverSleepSec=0, const std::string &serverLog="")
static int ClientTest::dump (ClientTest &client, SyncSource &source, const char *file)
 utility function for dumping items which are C strings with blank lines as separator
static int ClientTest::import (ClientTest &client, SyncSource &source, const char *file)
 utility function for importing items with blank lines as separator
static bool ClientTest::compare (ClientTest &client, const char *fileA, const char *fileB)
 utility function for comparing vCard and iCal files with the external synccompare.pl Perl script
virtual void ClientTest::postSync (int res, const std::string &logname)
 This is called after successful sync() calls (res == 0) as well as after unsuccessful ones (res != 1).
static void ClientTest::getTestData (const char *type, Config &config)
 A derived class can use this call to get default test cases, but still has to add callbacks which create sources and execute a sync session.
virtual void CheckSyncReport::check (int res, SyncReport &report) const
 checks that the sync completed as expected and throws CPPUnit exceptions if something is wrong

Variables

ClientListener syncListener

Detailed Description

The testing framework of the C++ client library is based on CPPUnit.

It fulfills several different goals:

Some of the design goals were:

The test runner "client-test" is implemented in client-test-main.cpp. It automatically assembles all CPPUnit tests it was linked against and runs them all if started without parameters. Output is ASCII. The return code indicates success or failure of any test. "-h|--help" print some usage information and a full list of all available tests. Tests or test groups as printed in that list can be given as command line parameters to run just these tests. Because tests do not communicate directly with the command line front-end, they must be passed parameters via environment variables. See the description of TestFileSource for further information about running those end-to-end synchronization tests.

The test runner itself also understands some environment variables: CLIENT_TEST_FAILURES can be set to a comma separated list of tests which are allowed to fail without affecting the return code of the test runner.

On Linux the test runner supports setting a timeout which is triggered if a test runs for more than the number of seconds set in the environment variable CLIENT_TEST_ALARM. This relies on signals and therefore is disabled in compilations on Windows with an ifdef HAVE_SIGNALS_H.

Because of the dependency on CPPUnit the testing needs to be enabled explicitly. This can be done separately for tests embedded in the object files of the library (unit tests) and the end-to-end synchronization (integration tests) which can be used with release versions of the library.

On POSIX systems the configure --enable-integration-test and --enable-unit-tests switches enable the testing. "make check" automatically executes the unit tests.

On Windows the Visual Studio project file build/win32/cppunit.sln was prepared to build the "client-test" executable. Because it uses the standard win32.vcproj, some changes are necessary to enable unit tests:

Unit tests are only found if they are pulled into the executable. On Linux this is done by searching for variables with a special name, created by the FUNAMBOL_TEST_SUITE_REGISTRATION() macro in test.h, and setting link flags on the fly. On Windows an additional C file with references to these variables is used instead. This is done by a Python script, thus python.exe must be installed and found in the search path of Visual Studio. Any suggestion how to avoid the dependency on external scripting tools without having to manually register tests in a central file is welcome...

The integration tests depend on auxiliary files (test/synccompare.pl and test/testcases) which must be found in the directory where the test is run. On Linux the makefile rules automatically copy these, but the Visual Studio project file does not. Note that test/synccompare.pl is written in Perl (and thus creates another external dependency) because a) C/C++ do not have a standard library to implement the complex regular pattern matching/replace done in that script and b) the script is also meant to be shipped with clients (SyncEvolution does that) and thus needs to run on as many systems as possible. Perl is still the most universally available scripting language for that purpose.

Adding new unit tests is best done by following the example in src/c++/common/base/util/BasicTime.cpp.

Regular testing of a server can be done by using the reference data provided together with ClientTest and synchronizing the server against simple files on the client side via a TestFileSource. This is what enabling the integration tests adds to the "client-test" binary. By keeping the client side fixed regressions in the server can be detected. Regular testing of the client library can be done by testing the current client library source against stable servers.

For testing a client based on the C++ library the client developer needs to implement the ClientTest interface. There are some additional requirements for the client's SyncSource implementations:

The TestFileSource is an example how the ClientTest interface could be implemented.


Define Documentation

#define ADD_TEST ( _class,
_function   )     addTest(new CppUnit::TestCaller<_class>(getName() + "::" #_function, &_class::_function, *this))

convenience macro for adding a test name like a function, to be used inside an instance of that class

Parameters:
_class class which contains the function
_function a function without parameters in that class

#define SOURCE_ASSERT ( _source,
_x   ) 

Value:

{ \
    CPPUNIT_ASSERT(_x); \
    CPPUNIT_ASSERT((_source) && (!(_source)->getReport() || (_source)->getReport()->getState() != SOURCE_ERROR)); \
}
check _x for true and then the status of the _source pointer

#define SOURCE_ASSERT_EQUAL ( _source,
_value,
_x   ) 

Value:

{ \
    CPPUNIT_ASSERT_EQUAL(_value, _x); \
    CPPUNIT_ASSERT((_source) && (!(_source)->getReport() || (_source)->getReport()->getState() != SOURCE_ERROR)); \
}
check that _x evaluates to a specific value and then the status of the _source pointer

#define SOURCE_ASSERT_MESSAGE ( _message,
_source,
_x   ) 

Value:

{ \
    CPPUNIT_ASSERT_MESSAGE((_message), (_x)); \
    CPPUNIT_ASSERT((_source) && (!(_source)->getReport() || (_source)->getReport()->getState() != SOURCE_ERROR)); \
}
same as SOURCE_ASSERT() with a specific failure message

#define SOURCE_ASSERT_NO_FAILURE ( _source,
_x   ) 

Value:

{ \
    CPPUNIT_ASSERT_NO_THROW(_x); \
    CPPUNIT_ASSERT((_source) && (!(_source)->getReport() || (_source)->getReport()->getState() != SOURCE_ERROR)); \
}
execute _x and then check the status of the _source pointer


Function Documentation

void CheckSyncReport::check ( int  res,
SyncReport report 
) const [virtual, inherited]

checks that the sync completed as expected and throws CPPUnit exceptions if something is wrong

Parameters:
res return code from SyncClient::sync()
report the sync report stored in the SyncClient

void ClientTest::getTestData ( const char *  type,
Config config 
) [static, inherited]

A derived class can use this call to get default test cases, but still has to add callbacks which create sources and execute a sync session.

Some of the test cases are compiled into the library, other depend on the auxiliary files from the "test" directory. Currently supported types:

void ClientTest::postSync ( int  res,
const std::string &  logname 
) [virtual, inherited]

This is called after successful sync() calls (res == 0) as well as after unsuccessful ones (res != 1).

The default implementation sleeps for the number of seconds specified when constructing this instance and copies the server log if one was named.

Parameters:
res result of sync()
logname base name of the current sync log (without ".client.[AB].log" suffix)

void ClientTest::registerTests (  )  [virtual, inherited]

This is the only function provided by ClientTest itself: it registers tests using this instance of ClientTest for later use during a test run.

Theinstance must remain valid until after the tests were run. To run them use a separate test runner, like the one from client-test-main.cpp.


Generated on Fri Apr 27 12:29:20 2007 for Funambol C++ Client Library by  doxygen 1.5.2