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 |
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 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
_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)); \ }
#define SOURCE_ASSERT_EQUAL | ( | _source, | |||
_value, | |||||
_x | ) |
Value:
{ \ CPPUNIT_ASSERT_EQUAL(_value, _x); \ CPPUNIT_ASSERT((_source) && (!(_source)->getReport() || (_source)->getReport()->getState() != SOURCE_ERROR)); \ }
#define SOURCE_ASSERT_MESSAGE | ( | _message, | |||
_source, | |||||
_x | ) |
Value:
{ \ CPPUNIT_ASSERT_MESSAGE((_message), (_x)); \ CPPUNIT_ASSERT((_source) && (!(_source)->getReport() || (_source)->getReport()->getState() != SOURCE_ERROR)); \ }
#define SOURCE_ASSERT_NO_FAILURE | ( | _source, | |||
_x | ) |
Value:
{ \ CPPUNIT_ASSERT_NO_THROW(_x); \ CPPUNIT_ASSERT((_source) && (!(_source)->getReport() || (_source)->getReport()->getState() != SOURCE_ERROR)); \ }
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
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.
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.