X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Finclude%2Fgnunet_testing_lib.h;h=72b5ede0423456570d73f361a57c58b10ee192ff;hb=a44744499d8f3df64cc1d15cd6b40b4b0e4a3683;hp=4503e7b9b83d0648ce565221f0a16497378a82a2;hpb=c7ed67bb39b321e0ab547b186b466aa6ef630ccf;p=oweals%2Fgnunet.git diff --git a/src/include/gnunet_testing_lib.h b/src/include/gnunet_testing_lib.h index 4503e7b9b..72b5ede04 100644 --- a/src/include/gnunet_testing_lib.h +++ b/src/include/gnunet_testing_lib.h @@ -1,10 +1,10 @@ /* This file is part of GNUnet - (C) 2008, 2009 Christian Grothoff (and other contributing authors) + Copyright (C) 2008, 2009, 2012 GNUnet e.V. GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2, or (at your + by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but @@ -14,25 +14,36 @@ You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ /** - * @file include/gnunet_testing_lib.h - * @brief convenience API for writing testcases for GNUnet - * Many testcases need to start and stop gnunetd, - * and this library is supposed to make that easier - * for TESTCASES. Normal programs should always - * use functions from gnunet_{util,arm}_lib.h. This API is - * ONLY for writing testcases! * @author Christian Grothoff + * + * @file + * Convenience API for writing testcases for GNUnet + * + * @defgroup testing Testing library + * Library for writing testcases for GNUnet. + * + * It can start/stop one or more peers on a system; testing is responsible for + * managing private keys, ports and paths; it is a low-level library that does + * not support higher-level functions such as P2P connection, topology + * management or distributed testbed maintenance (those are provided by the + * [Testbed service](@ref testbed)) + * + * @see [Documentation](https://gnunet.org/writing_testcases) + * + * @{ */ #ifndef GNUNET_TESTING_LIB_H #define GNUNET_TESTING_LIB_H #include "gnunet_util_lib.h" +#include "gnunet_statistics_service.h" +#include "gnunet_arm_service.h" #ifdef __cplusplus extern "C" @@ -42,297 +53,411 @@ extern "C" #endif #endif +/** + * Size of each hostkey in the hostkey file (in BYTES). + */ +#define GNUNET_TESTING_HOSTKEYFILESIZE sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey) + +/** + * The environmental variable, if set, that dictates where testing should place + * generated peer configurations + */ +#define GNUNET_TESTING_PREFIX "GNUNET_TESTING_PREFIX" /** - * Handle for a GNUnet daemon (technically a set of - * daemons; the handle is really for the master ARM - * daemon) started by the testing library. + * Handle for a system on which GNUnet peers are executed; + * a system is used for reserving unique paths and ports. */ -struct GNUNET_TESTING_Daemon; +struct GNUNET_TESTING_System; /** - * Prototype of a function that will be called whenever - * a daemon was started by the testing library. + * Handle for a GNUnet peer controlled by testing. + */ +struct GNUNET_TESTING_Peer; + + +/** + * Specification of a service that is to be shared among peers + */ +struct GNUNET_TESTING_SharedService +{ + /** + * The name of the service. + */ + const char *service; + + /** + * The configuration template for the service. Cannot be NULL + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * The number of peers which share an instance of the service. 0 for sharing + * among all peers + */ + unsigned int share; +}; + + +/** + * Create a system handle. There must only be one system handle per operating + * system. Uses a default range for allowed ports. Ports are still tested for + * availability. * - * @param cls closure - * @param id identifier for the daemon, NULL on error - * @param cfg configuration used by this daemon - * @param d handle for the daemon - * @param emsg error message (NULL on success) + * @param testdir only the directory name without any path. This is used for all + * service homes; the directory will be created in a temporary location + * depending on the underlying OS. This variable will be + * overridden with the value of the environmental variable + * GNUNET_TESTING_PREFIX, if it exists. + * @param trusted_ip the ip address which will be set as TRUSTED HOST in all + * service configurations generated to allow control connections from + * this ip. This can either be a single ip address or a network address + * in CIDR notation. + * @param hostname the hostname of the system we are using for testing; NULL for + * localhost + * @param shared_services NULL terminated array describing services that are to + * be shared among peers + * @return handle to this system, NULL on error */ -typedef void (*GNUNET_TESTING_NotifyDaemonRunning)(void *cls, - const struct GNUNET_PeerIdentity *id, - const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_TESTING_Daemon *d, - const char *emsg); +struct GNUNET_TESTING_System * +GNUNET_TESTING_system_create (const char *testdir, + const char *trusted_ip, + const char *hostname, + const struct GNUNET_TESTING_SharedService * + shared_services); /** - * Prototype of a function that will be called whenever - * two daemons are connected by the testing library. + * Create a system handle. There must only be one system + * handle per operating system. Use this function directly + * if multiple system objects are created for the same host + * (only really useful when testing --- or to make the port + * range configureable). * - * @param cls closure - * @param first peer id for first daemon - * @param second peer id for the second daemon - * @param first_cfg config for the first daemon - * @param second_cfg config for the second daemon - * @param first_daemon handle for the first daemon - * @param second_daemon handle for the second daemon - * @param emsg error message (NULL on success) + * @param testdir only the directory name without any path. This is used for + * all service homes; the directory will be created in a temporary + * location depending on the underlying OS. This variable will be + * overridden with the value of the environmental variable + * GNUNET_TESTING_PREFIX, if it exists. + * @param trusted_ip the ip address which will be set as TRUSTED HOST in all + * service configurations generated to allow control connections from + * this ip. This can either be a single ip address or a network address + * in CIDR notation. + * @param hostname the hostname of the system we are using for testing; NULL for + * localhost + * @param shared_services NULL terminated array describing services that are to + * be shared among peers + * @param lowport lowest port number this system is allowed to allocate (inclusive) + * @param highport highest port number this system is allowed to allocate (exclusive) + * @return handle to this system, NULL on error */ -typedef void (*GNUNET_TESTING_NotifyConnection)(void *cls, - const struct GNUNET_PeerIdentity *first, - const struct GNUNET_PeerIdentity *second, - const struct GNUNET_CONFIGURATION_Handle *first_cfg, - const struct GNUNET_CONFIGURATION_Handle *second_cfg, - struct GNUNET_TESTING_Daemon *first_daemon, - struct GNUNET_TESTING_Daemon *second_daemon, - const char *emsg); +struct GNUNET_TESTING_System * +GNUNET_TESTING_system_create_with_portrange (const char *testdir, + const char *trusted_ip, + const char *hostname, + const struct + GNUNET_TESTING_SharedService * + shared_services, + uint16_t lowport, + uint16_t highport); + /** - * Starts a GNUnet daemon. GNUnet must be installed on the target - * system and available in the PATH. The machine must furthermore be - * reachable via "ssh" (unless the hostname is "NULL") without the - * need to enter a password. + * Free system resources. * - * @param sched scheduler to use - * @param cfg configuration to use - * @param hostname name of the machine where to run GNUnet - * (use NULL for localhost). - * @param cb function to call with the result - * @param cb_cls closure for cb - * @return handle to the daemon (actual start will be completed asynchronously) + * @param system system to be freed + * @param remove_paths should the 'testdir' and all subdirectories + * be removed (clean up on shutdown)? */ -struct GNUNET_TESTING_Daemon * -GNUNET_TESTING_daemon_start (struct GNUNET_SCHEDULER_Handle *sched, - const struct GNUNET_CONFIGURATION_Handle *cfg, - const char *hostname, - GNUNET_TESTING_NotifyDaemonRunning cb, - void *cb_cls); +void +GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system, + int remove_paths); /** - * Prototype of a function that will be called when a - * particular operation was completed the testing library. + * Testing includes a number of pre-created hostkeys for + * faster peer startup. This function can be used to + * access the n-th key of those pre-created hostkeys; note + * that these keys are ONLY useful for testing and not + * secure as the private keys are part of the public + * GNUnet source code. * - * @param cls closure - * @param emsg NULL on success + * This is primarily a helper function used internally + * by 'GNUNET_TESTING_peer_configure'. + * + * @param system the testing system handle + * @param key_number desired pre-created hostkey to obtain + * @param id set to the peer's identity (hash of the public + * key; if NULL, GNUNET_SYSERR is returned immediately + * @return NULL on error (not enough keys) */ -typedef void (*GNUNET_TESTING_NotifyCompletion)(void *cls, - const char *emsg); +struct GNUNET_CRYPTO_EddsaPrivateKey * +GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system, + uint32_t key_number, + struct GNUNET_PeerIdentity *id); /** - * Stops a GNUnet daemon. + * Reserve a port for a peer. * - * @param d the daemon that should be stopped - * @param cb function called once the daemon was stopped - * @param cb_cls closure for cb + * @param system system to use for reservation tracking + * @return 0 if no free port was available */ -void GNUNET_TESTING_daemon_stop (struct GNUNET_TESTING_Daemon *d, - GNUNET_TESTING_NotifyCompletion cb, - void * cb_cls); +uint16_t +GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system); /** - * Changes the configuration of a GNUnet daemon. + * Release reservation of a TCP or UDP port for a peer + * (used during GNUNET_TESTING_peer_destroy). * - * @param d the daemon that should be modified - * @param cfg the new configuration for the daemon - * @param cb function called once the configuration was changed - * @param cb_cls closure for cb + * @param system system to use for reservation tracking + * @param port reserved port to release */ -void GNUNET_TESTING_daemon_reconfigure (struct GNUNET_TESTING_Daemon *d, - struct GNUNET_CONFIGURATION_Handle *cfg, - GNUNET_TESTING_NotifyCompletion cb, - void * cb_cls); +void +GNUNET_TESTING_release_port (struct GNUNET_TESTING_System *system, + uint16_t port); -/* - * Get the short name of a running peer + +/** + * Create a new configuration using the given configuration as a template; + * ports and paths will be modified to select available ports on the local + * system. The default configuration will be available in PATHS section under + * the option DEFAULTCONFIG after the call. SERVICE_HOME is also set in PATHS + * section to the temporary directory specific to this configuration. If we run + * out of "*port" numbers, return SYSERR. + * + * This is primarily a helper function used internally + * by 'GNUNET_TESTING_peer_configure'. * - * @param d the daemon handle + * @param system system to use to coordinate resource usage + * @param cfg template configuration to update + * @return #GNUNET_OK on success, + * #GNUNET_SYSERR on error - the configuration will + * be incomplete and should not be used there upon */ -char * -GNUNET_TESTING_daemon_get_shortname(struct GNUNET_TESTING_Daemon *d); +int +GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system, + struct GNUNET_CONFIGURATION_Handle *cfg); +// FIXME: add dual to 'release' ports again... + /** - * Establish a connection between two GNUnet daemons. + * Configure a GNUnet peer. GNUnet must be installed on the local + * system and available in the PATH. * - * @param d1 handle for the first daemon - * @param d2 handle for the second daemon - * @param timeout how long is the connection attempt - * allowed to take? - * @param cb function to call at the end - * @param cb_cls closure for cb + * @param system system to use to coordinate resource usage + * @param cfg configuration to use; will be UPDATED (to reflect needed + * changes in port numbers and paths) + * @param key_number number of the hostkey to use for the peer + * @param id identifier for the daemon, will be set, can be NULL + * @param emsg set to freshly allocated error message (set to NULL on success), + * can be NULL + * @return handle to the peer, NULL on error */ -void GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1, - struct GNUNET_TESTING_Daemon *d2, - struct GNUNET_TIME_Relative timeout, - GNUNET_TESTING_NotifyConnection cb, - void *cb_cls); +struct GNUNET_TESTING_Peer * +GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system, + struct GNUNET_CONFIGURATION_Handle *cfg, + uint32_t key_number, + struct GNUNET_PeerIdentity *id, + char **emsg); +/** + * Obtain the peer identity from a peer handle. + * + * @param peer peer handle for which we want the peer's identity + * @param id identifier for the daemon, will be set + */ +void +GNUNET_TESTING_peer_get_identity (struct GNUNET_TESTING_Peer *peer, + struct GNUNET_PeerIdentity *id); + /** - * Handle to a group of GNUnet peers. + * Start the peer. + * + * @param peer peer to start + * @return #GNUNET_OK on success, + * #GNUNET_SYSERR on error (i.e. peer already running) */ -struct GNUNET_TESTING_PeerGroup; +int +GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer); /** - * Start count gnunetd processes with the same set of transports and - * applications. The port numbers (any option called "PORT") will be - * adjusted to ensure that no two peers running on the same system - * have the same port(s) in their respective configurations. + * Stop the peer. This call is blocking as it kills the peer's main ARM process + * by sending a SIGTERM and waits on it. For asynchronous shutdown of peer, see + * GNUNET_TESTING_peer_stop_async(). * - * @param sched scheduler to use - * @param cfg configuration template to use - * @param total number of daemons to start - * @param cb function to call on each daemon that was started - * @param cb_cls closure for cb - * @param connect_callback function to call each time two hosts are connected - * @param connect_callback_cls closure for connect_callback - * @param hostnames space-separated list of hostnames to use, - * NULL to use localhost only - * @return NULL on error, otherwise handle to control peer group + * @param peer peer to stop + * @return #GNUNET_OK on success, + * #GNUNET_SYSERR on error (i.e. peer not running) */ -struct GNUNET_TESTING_PeerGroup * -GNUNET_TESTING_daemons_start (struct GNUNET_SCHEDULER_Handle *sched, - const struct GNUNET_CONFIGURATION_Handle *cfg, - unsigned int total, - GNUNET_TESTING_NotifyDaemonRunning cb, - void *cb_cls, - GNUNET_TESTING_NotifyConnection connect_callback, - void *connect_callback_cls, - const char *hostnames); +int +GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer); /** - * Shutdown all peers started in the given group. - * - * @param pg handle to the peer group + * Destroy the peer. Releases resources locked during peer configuration. + * If the peer is still running, it will be stopped AND a warning will be + * printed (users of the API should stop the peer explicitly first). + * + * @param peer peer to destroy */ void -GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg); +GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer); /** - * Handle to an entire testbed of GNUnet peers. + * Sends SIGTERM to the peer's main process + * + * @param peer the handle to the peer + * @return #GNUNET_OK if successful; #GNUNET_SYSERR if the main process is NULL + * or upon any error while sending SIGTERM */ -struct GNUNET_TESTING_Testbed; +int +GNUNET_TESTING_peer_kill (struct GNUNET_TESTING_Peer *peer); /** - * Topologies supported for testbeds. + * Waits for a peer to terminate. The peer's main process will also be destroyed. + * + * @param peer the handle to the peer + * @return #GNUNET_OK if successful; #GNUNET_SYSERR if the main process is NULL + * or upon any error while waiting */ -enum GNUNET_TESTING_Topology -{ - /** - * A clique (everyone connected to everyone else). - */ - GNUNET_TESTING_TOPOLOGY_CLIQUE, +int +GNUNET_TESTING_peer_wait (struct GNUNET_TESTING_Peer *peer); - /** - * Small-world network (2d torus plus random links). - */ - GNUNET_TESTING_TOPOLOGY_SMALL_WORLD, - /** - * Ring topology. - */ - GNUNET_TESTING_TOPOLOGY_RING, +/** + * Callback to inform whether the peer is running or stopped. + * + * @param cls the closure given to GNUNET_TESTING_peer_stop_async() + * @param peer the respective peer whose status is being reported + * @param success #GNUNET_YES if the peer is stopped; #GNUNET_SYSERR upon any + * error + */ +typedef void +(*GNUNET_TESTING_PeerStopCallback) (void *cls, + struct GNUNET_TESTING_Peer *peer, + int success); - /** - * 2-d torus. - */ - GNUNET_TESTING_TOPOLOGY_2D_TORUS, - /** - * Random graph. - */ - GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI, +/** + * Stop a peer asynchronously using ARM API. Peer's shutdown is signaled + * through the GNUNET_TESTING_PeerStopCallback(). + * + * @param peer the peer to stop + * @param cb the callback to signal peer shutdown + * @param cb_cls closure for the above callback + * @return GNUNET_OK upon successfully giving the request to the ARM API (this + * does not mean that the peer is successfully stopped); GNUNET_SYSERR + * upon any error. + */ +int +GNUNET_TESTING_peer_stop_async (struct GNUNET_TESTING_Peer *peer, + GNUNET_TESTING_PeerStopCallback cb, + void *cb_cls); - /* - * Certain percentage of peers are unable to communicate directly - * replicating NAT conditions - */ - GNUNET_TESTING_TOPOLOGY_INTERNAT, - /** - * All peers are disconnected. - */ - GNUNET_TESTING_TOPOLOGY_NONE -}; +/** + * Cancel a previous asynchronous peer stop request. + * GNUNET_TESTING_peer_stop_async() should have been called before on the given + * peer. It is an error to call this function if the peer stop callback was + * already called + * + * @param peer the peer on which GNUNET_TESTING_peer_stop_async() was called + * before. + */ +void +GNUNET_TESTING_peer_stop_async_cancel (struct GNUNET_TESTING_Peer *peer); /** - * Start "count" GNUnet daemons with a particular topology. + * Signature of the 'main' function for a (single-peer) testcase that + * is run using #GNUNET_TESTING_peer_run(). * - * @param sched scheduler to use - * @param cfg configuration template to use - * @param count number of peers the testbed should have - * @param topology desired topology (enforced via F2F) - * @param cb function to call on each daemon that was started - * @param cb_cls closure for cb - * @param hostname where to run the peers; can be NULL (to run - * everything on localhost). Additional - * hosts can be specified using a NULL-terminated list of - * varargs, hosts will then be used round-robin from that - * list. - * @return handle to control the testbed + * @param cls closure + * @param cfg configuration of the peer that was started + * @param peer identity of the peer that was created */ -struct GNUNET_TESTING_Testbed * -GNUNET_TESTING_testbed_start (struct GNUNET_SCHEDULER_Handle *sched, - const struct GNUNET_CONFIGURATION_Handle *cfg, - unsigned int count, - enum GNUNET_TESTING_Topology topology, - GNUNET_TESTING_NotifyDaemonRunning cb, - void *cb_cls, - const char *hostname, - ...); +typedef void +(*GNUNET_TESTING_TestMain) (void *cls, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Peer *peer); /** - * Stop all of the daemons started with the start function. + * Start a single peer and run a test using the testing library. + * Starts a peer using the given configuration and then invokes the + * given callback. This function ALSO initializes the scheduler loop + * and should thus be called directly from "main". The testcase + * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'. * - * @param tb handle for the testbed - * @param cb function to call when done - * @param cb_cls closure for cb + * @param testdir only the directory name without any path. This is used for + * all service homes; the directory will be created in a temporary + * location depending on the underlying OS + * @param cfgfilename name of the configuration file to use; + * use NULL to only run with defaults + * @param tm main function of the testcase + * @param tm_cls closure for 'tm' + * @return 0 on success, 1 on error */ -void -GNUNET_TESTING_testbed_stop (struct GNUNET_TESTING_Testbed *tb, - GNUNET_TESTING_NotifyCompletion cb, - void *cb_cls ); +int +GNUNET_TESTING_peer_run (const char *testdir, + const char *cfgfilename, + GNUNET_TESTING_TestMain tm, + void *tm_cls); /** - * Simulate churn in the testbed by stopping some peers (and possibly - * re-starting others if churn is called multiple times). This - * function can only be used to create leave-join churn (peers "never" - * leave for good). First "voff" random peers that are currently - * online will be taken offline; then "von" random peers that are then - * offline will be put back online. No notifications will be - * generated for any of these operations except for the callback upon - * completion. Note that the implementation is at liberty to keep - * the ARM service itself (but none of the other services or daemons) - * running even though the "peer" is being varied offline. + * Start a single service (no ARM, except of course if the given + * service name is 'arm') and run a test using the testing library. + * Starts a service using the given configuration and then invokes the + * given callback. This function ALSO initializes the scheduler loop + * and should thus be called directly from "main". The testcase + * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'. + * + * This function is useful if the testcase is for a single service + * and if that service doesn't itself depend on other services. * - * @param tb handle for the testbed - * @param voff number of peers that should go offline - * @param von number of peers that should come back online; - * must be zero on first call (since "testbed_start" - * always starts all of the peers) - * @param cb function to call at the end - * @param cb_cls closure for cb + * @param testdir only the directory name without any path. This is used for + * all service homes; the directory will be created in a temporary + * location depending on the underlying OS + * @param service_name name of the service to run + * @param cfgfilename name of the configuration file to use; + * use NULL to only run with defaults + * @param tm main function of the testcase + * @param tm_cls closure for @a tm + * @return 0 on success, 1 on error */ -void -GNUNET_TESTING_testbed_churn (struct GNUNET_TESTING_Testbed *tb, - unsigned int voff, - unsigned int von, - GNUNET_TESTING_NotifyCompletion cb, - void *cb_cls); +int +GNUNET_TESTING_service_run (const char *testdir, + const char *service_name, + const char *cfgfilename, + GNUNET_TESTING_TestMain tm, + void *tm_cls); + + +/** + * Sometimes we use the binary name to determine which specific + * test to run. In those cases, the string after the last "_" + * in 'argv[0]' specifies a string that determines the configuration + * file or plugin to use. + * + * This function returns the respective substring, taking care + * of issues such as binaries ending in '.exe' on W32. + * + * @param argv0 the name of the binary + * @return string between the last '_' and the '.exe' (or the end of the string), + * NULL if argv0 has no '_' + */ +char * +GNUNET_TESTING_get_testname_from_underscore (const char *argv0); #if 0 /* keep Emacsens' auto-indent happy */ @@ -343,3 +468,5 @@ GNUNET_TESTING_testbed_churn (struct GNUNET_TESTING_Testbed *tb, #endif #endif + +/** @} */ /* end of group */