X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Finclude%2Fgnunet_testing_lib.h;h=c15116876f3496d44fe460b54aecaff3340dde63;hb=00dfa7c87e756ae8f301d59896850e1cb1a3e611;hp=35a41b4906e37eb7335cbb240d58c71fb6908044;hpb=81e041f4ea19985a91a3b2ee5a857a26ff3a2d59;p=oweals%2Fgnunet.git diff --git a/src/include/gnunet_testing_lib.h b/src/include/gnunet_testing_lib.h index 35a41b490..c15116876 100644 --- a/src/include/gnunet_testing_lib.h +++ b/src/include/gnunet_testing_lib.h @@ -1,6 +1,6 @@ /* This file is part of GNUnet - (C) 2008, 2009 Christian Grothoff (and other contributing authors) + (C) 2008, 2009, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -20,12 +20,13 @@ /** * @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! + * @brief convenience API for writing testcases for GNUnet; + * 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 in gnunet_testbed_service.h) * @author Christian Grothoff */ @@ -34,6 +35,7 @@ #include "gnunet_util_lib.h" #include "gnunet_statistics_service.h" +#include "gnunet_arm_service.h" #ifdef __cplusplus extern "C" @@ -43,974 +45,400 @@ extern "C" #endif #endif -#define HOSTKEYFILESIZE 914 - /** - * Handle for a GNUnet daemon (technically a set of - * daemons; the handle is really for the master ARM - * daemon) started by the testing library. + * Size of each hostkey in the hostkey file (in BYTES). */ -struct GNUNET_TESTING_Daemon; +#define GNUNET_TESTING_HOSTKEYFILESIZE sizeof (struct GNUNET_CRYPTO_EccPrivateKey) /** - * Linked list of hostnames and ports to use for starting daemons. + * Handle for a system on which GNUnet peers are executed; + * a system is used for reserving unique paths and ports. */ -struct GNUNET_TESTING_Host -{ - /** - * Pointer to next item in the list. - */ - struct GNUNET_TESTING_Host *next; - - /** - * Hostname to connect to. - */ - char *hostname; - - /** - * Username to use when connecting (may be null). - */ - char *username; - - /** - * Port to use for SSH connection (used for ssh - * connection forwarding, 0 to let ssh decide) - */ - uint16_t port; -}; +struct GNUNET_TESTING_System; -/** - * Prototype of a function that will be called whenever - * a daemon was started by the testing library. - * - * @param cls closure - * @param id identifier for the daemon, NULL on error - * @param d handle for the daemon - * @param emsg error message (NULL on success) - */ -typedef void (*GNUNET_TESTING_NotifyHostkeyCreated)(void *cls, - const struct GNUNET_PeerIdentity *id, - struct GNUNET_TESTING_Daemon *d, - const char *emsg); /** - * Prototype of a function that will be called whenever - * a daemon was started by the testing library. - * - * @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) + * Handle for a GNUnet peer controlled by testing. */ -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_Peer; -/** - * Handle to an entire testbed of GNUnet peers. - */ -struct GNUNET_TESTING_Testbed; /** - * Phases of starting GNUnet on a system. + * Specification of a service that is to be shared among peers */ -enum GNUNET_TESTING_StartPhase +struct GNUNET_TESTING_SharedService { /** - * Copy the configuration file to the target system. - */ - SP_COPYING, - - /** - * Configuration file has been copied, generate hostkey. - */ - SP_COPIED, - - /** - * Create the hostkey for the peer. - */ - SP_HOSTKEY_CREATE, - - /** - * Hostkey generated, wait for topology to be finished. + * The name of the service. */ - SP_HOSTKEY_CREATED, + const char *service; /** - * Topology has been created, now start ARM. + * The configuration template for the service. Cannot be NULL */ - SP_TOPOLOGY_SETUP, + const struct GNUNET_CONFIGURATION_Handle *cfg; /** - * ARM has been started, check that it has properly daemonized and - * then try to connect to the CORE service (which should be - * auto-started by ARM). + * The number of peers which share an instance of the service. 0 for sharing + * among all peers */ - SP_START_ARMING, - - /** - * We're waiting for CORE to start. - */ - SP_START_CORE, - - /** - * CORE is up, now make sure we get the HELLO for this peer. - */ - SP_GET_HELLO, - - /** - * Core has notified us that we've established a connection to the service. - * The main FSM halts here and waits to be moved to UPDATE or CLEANUP. - */ - SP_START_DONE, - - /** - * We've been asked to terminate the instance and are now waiting for - * the remote command to stop the gnunet-arm process and delete temporary - * files. - */ - SP_SHUTDOWN_START, - - /** - * We've received a configuration update and are currently waiting for - * the copy process for the update to complete. Once it is, we will - * return to "SP_START_DONE" (and rely on ARM to restart all affected - * services). - */ - SP_CONFIG_UPDATE + unsigned int share; }; -/** - * Prototype of a function that will be called when a - * particular operation was completed the testing library. - * - * @param cls closure - * @param emsg NULL on success - */ -typedef void (*GNUNET_TESTING_NotifyCompletion)(void *cls, - const char *emsg); /** - * Prototype of a function that will be called with the - * number of connections created for a particular topology. - * - * @param cls closure - * @param num_connections the number of connections created + * 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 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 + */ +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); + + +/** + * 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 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 + */ +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); + + +/** + * Free system resources. + * + * @param system system to be freed + * @param remove_paths should the 'testdir' and all subdirectories + * be removed (clean up on shutdown)? */ -typedef void (*GNUNET_TESTING_NotifyConnections)(void *cls, - unsigned int num_connections); - -/** - * Handle for a GNUnet daemon (technically a set of - * daemons; the handle is really for the master ARM - * daemon) started by the testing library. - */ -struct GNUNET_TESTING_Daemon -{ - /** - * Our configuration. - */ - struct GNUNET_CONFIGURATION_Handle *cfg; - - /** - * At what time to give up starting the peer - */ - struct GNUNET_TIME_Absolute max_timeout; - - /** - * Host to run GNUnet on. - */ - char *hostname; - - /** - * Port to use for ssh, NULL to let system choose default. - */ - char *ssh_port_str; - - /** - * Result of GNUNET_i2s of this peer, - * for printing - */ - char *shortname; - - /** - * Username we are using. - */ - char *username; - - /** - * Name of the configuration file - */ - char *cfgfile; - - /** - * Callback to inform initiator that the peer's - * hostkey has been created. - */ - GNUNET_TESTING_NotifyHostkeyCreated hostkey_callback; - - /** - * Closure for hostkey creation callback. - */ - void *hostkey_cls; - - /** - * Function to call when the peer is running. - */ - GNUNET_TESTING_NotifyDaemonRunning cb; - - /** - * Closure for cb. - */ - void *cb_cls; - - /** - * Arguments from "daemon_stop" call. - */ - GNUNET_TESTING_NotifyCompletion dead_cb; - - /** - * Closure for 'dead_cb'. - */ - void *dead_cb_cls; - - /** - * Arguments from "daemon_stop" call. - */ - GNUNET_TESTING_NotifyCompletion update_cb; - - /** - * Closure for 'update_cb'. - */ - void *update_cb_cls; - - /** - * Identity of this peer (once started). - */ - struct GNUNET_PeerIdentity id; - - /** - * Flag to indicate that we've already been asked - * to terminate (but could not because some action - * was still pending). - */ - int dead; - - /** - * GNUNET_YES if the hostkey has been created - * for this peer, GNUNET_NO otherwise. - */ - int have_hostkey; - - /** - * PID of the process that we started last. - */ - struct GNUNET_OS_Process *proc; - - /** - * In which phase are we during the start of - * this process? - */ - enum GNUNET_TESTING_StartPhase phase; - - /** - * ID of the current task. - */ - GNUNET_SCHEDULER_TaskIdentifier task; - - /** - * Handle to the server. - */ - struct GNUNET_CORE_Handle *server; - - /** - * Handle to the transport service of this peer - */ - struct GNUNET_TRANSPORT_Handle *th; - - /** - * HELLO message for this peer - */ - struct GNUNET_HELLO_Message *hello; - - /** - * Handle to a pipe for reading the hostkey. - */ - struct GNUNET_DISK_PipeHandle *pipe_stdout; - - /** - * Output from gnunet-peerinfo is read into this buffer. - */ - char hostkeybuf[105]; - - /** - * Current position in 'hostkeybuf' (for reading from gnunet-peerinfo) - */ - unsigned int hostkeybufpos; - - /** - * Set to GNUNET_YES once the peer is up. - */ - int running; - - /** - * Used to tell shutdown not to remove configuration for the peer - * (if it's going to be restarted later) - */ - int churn; -}; - - -/** - * Handle to a group of GNUnet peers. - */ -struct GNUNET_TESTING_PeerGroup; +void +GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system, + int remove_paths); /** - * Prototype of a function that will be called whenever - * two daemons are connected by 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 first peer id for first daemon - * @param second peer id for the second daemon - * @param distance distance between the connected peers - * @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) - */ -typedef void (*GNUNET_TESTING_NotifyConnection)(void *cls, - const struct GNUNET_PeerIdentity *first, - const struct GNUNET_PeerIdentity *second, - uint32_t distance, - 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); - -/** - * Prototype of a callback function indicating that two peers - * are currently connected. + * This is primarily a helper function used internally + * by 'GNUNET_TESTING_peer_configure'. * - * @param cls closure - * @param first peer id for first daemon - * @param second peer id for the second daemon - * @param distance distance between the connected peers - * @param emsg error message (NULL on success) + * @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_NotifyTopology)(void *cls, - const struct GNUNET_PeerIdentity *first, - const struct GNUNET_PeerIdentity *second, - const char *emsg); +struct GNUNET_CRYPTO_EccPrivateKey * +GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system, + uint32_t key_number, + struct GNUNET_PeerIdentity *id); -/** - * 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. - * - * @param cfg configuration to use - * @param timeout how long to wait starting up peers - * @param pretend GNUNET_YES to set up files but not start peer GNUNET_NO - * to really start the peer (default) - * @param hostname name of the machine where to run GNUnet - * (use NULL for localhost). - * @param ssh_username ssh username to use when connecting to hostname - * @param sshport port to pass to ssh process when connecting to hostname - * @param hostkey pointer to a hostkey to be written to disk (instead of being generated) - * @param hostkey_callback function to call once the hostkey has been - * generated for this peer, but it hasn't yet been started - * (NULL to start immediately, otherwise waits on GNUNET_TESTING_daemon_continue_start) - * @param hostkey_cls closure for hostkey callback - * @param cb function to call once peer is up, or failed to start - * @param cb_cls closure for cb - * @return handle to the daemon (actual start will be completed asynchronously) - */ -struct GNUNET_TESTING_Daemon * -GNUNET_TESTING_daemon_start (const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_TIME_Relative timeout, - int pretend, - const char *hostname, - const char *ssh_username, - uint16_t sshport, - const char *hostkey, - GNUNET_TESTING_NotifyHostkeyCreated - hostkey_callback, void *hostkey_cls, - GNUNET_TESTING_NotifyDaemonRunning cb, - void *cb_cls); /** - * Continues GNUnet daemon startup when user wanted to be notified - * once a hostkey was generated (for creating friends files, blacklists, - * etc.). + * Reserve a port for a peer. * - * @param daemon the daemon to finish starting + * @param system system to use for reservation tracking + * @return 0 if no free port was available */ -void -GNUNET_TESTING_daemon_continue_startup(struct GNUNET_TESTING_Daemon *daemon); +uint16_t +GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system); -/** - * Check whether the given daemon is running. - * - * @param daemon the daemon to check - * - * @return GNUNET_YES if the daemon is up, GNUNET_NO if the - * daemon is down, GNUNET_SYSERR on error. - */ -int -GNUNET_TESTING_daemon_running (struct GNUNET_TESTING_Daemon *daemon); /** - * Restart (stop and start) 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 restarted - * @param cb function called once the daemon is (re)started - * @param cb_cls closure for cb + * @param system system to use for reservation tracking + * @param port reserved port to release */ void -GNUNET_TESTING_daemon_restart (struct GNUNET_TESTING_Daemon *d, - GNUNET_TESTING_NotifyDaemonRunning cb, void *cb_cls); +GNUNET_TESTING_release_port (struct GNUNET_TESTING_System *system, + uint16_t port); -/** - * Start a peer that has previously been stopped using the daemon_stop - * call (and files weren't deleted and the allow restart flag) - * - * @param daemon the daemon to start (has been previously stopped) - * @param timeout how long to wait for restart - * @param cb the callback for notification when the peer is running - * @param cb_cls closure for the callback - */ -void -GNUNET_TESTING_daemon_start_stopped (struct GNUNET_TESTING_Daemon *daemon, - struct GNUNET_TIME_Relative timeout, - GNUNET_TESTING_NotifyDaemonRunning cb, - void *cb_cls); /** - * Get a certain testing daemon handle. - * - * @param pg handle to the set of running peers - * @param position the number of the peer to return - */ -struct GNUNET_TESTING_Daemon * -GNUNET_TESTING_daemon_get (struct GNUNET_TESTING_PeerGroup *pg, - unsigned int position); - -/* - * Get a daemon by peer identity, so callers can - * retrieve the daemon without knowing it's offset. + * 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. * - * @param pg the peer group to retrieve the daemon from - * @param peer_id the peer identity of the daemon to retrieve + * This is primarily a helper function used internally + * by 'GNUNET_TESTING_peer_configure'. * - * @return the daemon on success, or NULL if no such peer identity is found + * @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 */ -struct GNUNET_TESTING_Daemon * -GNUNET_TESTING_daemon_get_by_id (struct GNUNET_TESTING_PeerGroup *pg, - struct GNUNET_PeerIdentity *peer_id); - -/** - * Stops a GNUnet daemon. - * - * @param d the daemon that should be stopped - * @param timeout how long to wait for process for shutdown to complete - * @param cb function called once the daemon was stopped - * @param cb_cls closure for cb - * @param delete_files GNUNET_YES to remove files, GNUNET_NO - * to leave them (i.e. for restarting at a later time, - * or logfile inspection once finished) - * @param allow_restart GNUNET_YES to restart peer later (using this API) - * GNUNET_NO to kill off and clean up for good - */ -void -GNUNET_TESTING_daemon_stop (struct GNUNET_TESTING_Daemon *d, - struct GNUNET_TIME_Relative timeout, - GNUNET_TESTING_NotifyCompletion cb, void *cb_cls, - int delete_files, int allow_restart); +int +GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system, + struct GNUNET_CONFIGURATION_Handle *cfg); +// FIXME: add dual to 'release' ports again... /** - * Changes the configuration of a GNUnet daemon. + * Configure a GNUnet peer. GNUnet must be installed on the local + * system and available in the PATH. * - * @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 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_daemon_reconfigure (struct GNUNET_TESTING_Daemon *d, - struct GNUNET_CONFIGURATION_Handle *cfg, - GNUNET_TESTING_NotifyCompletion 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); /** - * Establish a connection between two GNUnet daemons. + * Obtain the peer identity from a peer handle. * - * @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 max_connect_attempts how many times should we try to reconnect - * (within timeout) - * @param send_hello GNUNET_YES to send the HELLO, GNUNET_NO to assume - * the HELLO has already been exchanged - * @param cb function to call at the end - * @param cb_cls closure for cb + * @param peer peer handle for which we want the peer's identity + * @param id identifier for the daemon, will be set */ void -GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1, - struct GNUNET_TESTING_Daemon *d2, - struct GNUNET_TIME_Relative timeout, - unsigned int max_connect_attempts, - int send_hello, - GNUNET_TESTING_NotifyConnection cb, - void *cb_cls); - - +GNUNET_TESTING_peer_get_identity (struct GNUNET_TESTING_Peer *peer, + struct GNUNET_PeerIdentity *id); /** - * Start count gnunet instances 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. - * - * @param cfg configuration template to use - * @param total number of daemons to start - * @param max_concurrent_connections for testing, how many peers can -* we connect to simultaneously - * @param max_concurrent_ssh when starting with ssh, how many ssh - * connections will we allow at once (based on remote hosts allowed!) - * @param timeout total time allowed for peers to start - * @param hostkey_callback function to call on each peers hostkey generation - * if NULL, peers will be started by this call, if non-null, - * GNUNET_TESTING_daemons_continue_startup must be called after - * successful hostkey generation - * @param hostkey_cls closure for hostkey callback - * @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 linked list of host structs to use to start peers on - * (NULL to run on localhost only) + * Start the peer. * - * @return NULL on error, otherwise handle to control peer group + * @param peer peer to start + * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer already running) */ -struct GNUNET_TESTING_PeerGroup * -GNUNET_TESTING_daemons_start (const struct GNUNET_CONFIGURATION_Handle *cfg, - unsigned int total, - unsigned int max_concurrent_connections, - unsigned int max_concurrent_ssh, - struct GNUNET_TIME_Relative timeout, - GNUNET_TESTING_NotifyHostkeyCreated - hostkey_callback, void *hostkey_cls, - GNUNET_TESTING_NotifyDaemonRunning cb, - void *cb_cls, - GNUNET_TESTING_NotifyConnection - connect_callback, void *connect_callback_cls, - const struct GNUNET_TESTING_Host *hostnames); +int +GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer); -/** - * Function which continues a peer group starting up - * after successfully generating hostkeys for each peer. - * - * @param pg the peer group to continue starting - */ -void -GNUNET_TESTING_daemons_continue_startup(struct GNUNET_TESTING_PeerGroup *pg); /** - * Restart all peers in the given group. + * 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 pg the handle to the peer group - * @param callback function to call on completion (or failure) - * @param callback_cls closure for the callback function + * @param peer peer to stop + * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer not running) */ -void -GNUNET_TESTING_daemons_restart (struct GNUNET_TESTING_PeerGroup *pg, - GNUNET_TESTING_NotifyCompletion callback, - void *callback_cls); +int +GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer); /** - * Shutdown all peers started in the given 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 pg handle to the peer group - * @param timeout how long to wait for shutdown - * @param cb callback to notify upon success or failure - * @param cb_cls closure for cb + * @param peer peer to destroy */ void -GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg, - struct GNUNET_TIME_Relative timeout, - GNUNET_TESTING_NotifyCompletion cb, - void *cb_cls); +GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer); /** - * Count the number of running peers. - * - * @param pg handle for the peer group + * Sends SIGTERM to the peer's main process * - * @return the number of currently running peers in the peer group + * @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 */ -unsigned int -GNUNET_TESTING_daemons_running (struct GNUNET_TESTING_PeerGroup *pg); +int +GNUNET_TESTING_peer_kill (struct GNUNET_TESTING_Peer *peer); -/** - * Simulate churn 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. - * - * @param pg handle for the peer group - * @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 timeout how long to wait for operations to finish before - * giving up - * @param cb function to call at the end - * @param cb_cls closure for cb - */ -void -GNUNET_TESTING_daemons_churn (struct GNUNET_TESTING_PeerGroup *pg, - unsigned int voff, - unsigned int von, - struct GNUNET_TIME_Relative timeout, - GNUNET_TESTING_NotifyCompletion cb, - void *cb_cls); /** - * Callback function to process statistic values. + * Waits for a peer to terminate. The peer's main process will also be destroyed. * - * @param cls closure - * @param peer the peer the statistics belong to - * @param subsystem name of subsystem that created the statistic - * @param name the name of the datum - * @param value the current value - * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not - * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration + * @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 */ -typedef int (*GNUNET_TESTING_STATISTICS_Iterator) (void *cls, - const struct GNUNET_PeerIdentity *peer, - const char *subsystem, - const char *name, - uint64_t value, - int is_persistent); - -/** - * Iterate over all (running) peers in the peer group, retrieve - * all statistics from each. - */ -void -GNUNET_TESTING_get_statistics (struct GNUNET_TESTING_PeerGroup *pg, - GNUNET_STATISTICS_Callback cont, - GNUNET_TESTING_STATISTICS_Iterator proc, void *cls); - -/** - * Topologies supported for testbeds. - */ -enum GNUNET_TESTING_Topology -{ - /** - * A clique (everyone connected to everyone else). - */ - GNUNET_TESTING_TOPOLOGY_CLIQUE, - - /** - * Small-world network (2d torus plus random links). - */ - GNUNET_TESTING_TOPOLOGY_SMALL_WORLD, - - /** - * Small-world network (ring plus random links). - */ - GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING, - - /** - * Ring topology. - */ - GNUNET_TESTING_TOPOLOGY_RING, - - /** - * 2-d torus. - */ - GNUNET_TESTING_TOPOLOGY_2D_TORUS, - - /** - * Random graph. - */ - GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI, - - /** - * Certain percentage of peers are unable to communicate directly - * replicating NAT conditions - */ - GNUNET_TESTING_TOPOLOGY_INTERNAT, - - /** - * Scale free topology. - */ - GNUNET_TESTING_TOPOLOGY_SCALE_FREE, - - /** - * Straight line topology. - */ - GNUNET_TESTING_TOPOLOGY_LINE, - - /** - * All peers are disconnected. - */ - GNUNET_TESTING_TOPOLOGY_NONE, - - /** - * Read a topology from a given file. - */ - GNUNET_TESTING_TOPOLOGY_FROM_FILE -}; - -/** - * Options for connecting a topology. - */ -enum GNUNET_TESTING_TopologyOption -{ - /** - * Try to connect all peers specified in the topology. - */ - GNUNET_TESTING_TOPOLOGY_OPTION_ALL, - - /** - * Choose a random subset of connections to create. - */ - GNUNET_TESTING_TOPOLOGY_OPTION_RANDOM, - - /** - * Create at least X connections for each peer. - */ - GNUNET_TESTING_TOPOLOGY_OPTION_MINIMUM, - - /** - * Using a depth first search, create one connection - * per peer. If any are missed (graph disconnected) - * start over at those peers until all have at least one - * connection. - */ - GNUNET_TESTING_TOPOLOGY_OPTION_DFS, - - /** - * Find the N closest peers to each allowed peer in the - * topology and make sure a connection to those peers - * exists in the connect topology. - */ - GNUNET_TESTING_TOPOLOGY_OPTION_ADD_CLOSEST, - - /** - * No options specified. - */ - GNUNET_TESTING_TOPOLOGY_OPTION_NONE -}; +int +GNUNET_TESTING_peer_wait (struct GNUNET_TESTING_Peer *peer); /** - * Get a topology from a string input. + * Callback to inform whether the peer is running or stopped. * - * @param topology where to write the retrieved topology - * @param topology_string The string to attempt to - * get a configuration value from - * @return GNUNET_YES if topology string matched a - * known topology, GNUNET_NO if not + * @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 */ -int -GNUNET_TESTING_topology_get(enum GNUNET_TESTING_Topology *topology, - const char * topology_string); +typedef void (*GNUNET_TESTING_PeerStopCallback) (void *cls, + struct GNUNET_TESTING_Peer * + peer, + int success); + /** - * Get connect topology option from string input. + * Stop a peer asynchronously using ARM API. Peer's shutdown is signaled + * through the GNUNET_TESTING_PeerStopCallback(). * - * @param topology_option where to write the retrieved topology - * @param topology_string The string to attempt to - * get a configuration value from - * @return GNUNET_YES if topology string matched a - * known topology, GNUNET_NO if not + * @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_topology_option_get(enum GNUNET_TESTING_TopologyOption *topology_option, - const char * topology_string); +GNUNET_TESTING_peer_stop_async (struct GNUNET_TESTING_Peer *peer, + GNUNET_TESTING_PeerStopCallback cb, + void *cb_cls); /** - * Takes a peer group and creates a topology based on the - * one specified. Creates a topology means generates friend - * files for the peers so they can only connect to those allowed - * by the topology. This will only have an effect once peers - * are started if the FRIENDS_ONLY option is set in the base - * config. - * - * Also takes an optional restrict topology which - * disallows direct connections UNLESS they are specified in - * the restricted topology. - * - * A simple example; if the topology option is set to LINE - * peers can ONLY connect in a LINE. However, if the topology - * option is set to 2D-torus and the restrict option is set to - * line with restrict_transports equal to "tcp udp", then peers - * may connect in a 2D-torus, but will be restricted to tcp and - * udp connections only in a LINE. Generally it only makes - * sense to do this if restrict_topology is a subset of topology. - * - * For testing peer discovery, etc. it is generally better to - * leave restrict_topology as GNUNET_TESTING_TOPOLOGY_NONE and - * then use the connect_topology function to restrict the initial - * connection set. - * - * @param pg the peer group struct representing the running peers - * @param topology which topology to connect the peers in - * @param restrict_topology allow only direct connections in this topology, - * based on those listed in restrict_transports, set to - * GNUNET_TESTING_TOPOLOGY_NONE for no restrictions - * @param restrict_transports space delimited list of transports to blacklist - * to create restricted topology, NULL for 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 * - * @return the maximum number of connections were all allowed peers - * connected to each other - */ -unsigned int -GNUNET_TESTING_create_topology (struct GNUNET_TESTING_PeerGroup *pg, - enum GNUNET_TESTING_Topology topology, - enum GNUNET_TESTING_Topology restrict_topology, - const char *restrict_transports); - -/** - * Iterate over all (running) peers in the peer group, retrieve - * all connections that each currently has. - * - * @param pg the peer group we are concerned with - * @param cb callback for topology information - * @param cls closure for callback + * @param peer the peer on which GNUNET_TESTING_peer_stop_async() was called + * before. */ void -GNUNET_TESTING_get_topology (struct GNUNET_TESTING_PeerGroup *pg, - GNUNET_TESTING_NotifyTopology cb, void *cls); +GNUNET_TESTING_peer_stop_async_cancel (struct GNUNET_TESTING_Peer *peer); -/** - * Stop the connection process temporarily. - * - * @param pg the peer group to stop connecting - */ -void GNUNET_TESTING_stop_connections(struct GNUNET_TESTING_PeerGroup *pg); /** - * Resume the connection process. + * Signature of the 'main' function for a (single-peer) testcase that + * is run using 'GNUNET_TESTING_peer_run'. * - * @param pg the peer group to resume connecting + * @param cls closure + * @param cfg configuration of the peer that was started + * @param peer identity of the peer that was created */ -void GNUNET_TESTING_resume_connections(struct GNUNET_TESTING_PeerGroup *pg); +typedef void (*GNUNET_TESTING_TestMain) (void *cls, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TESTING_Peer *peer); + /** - * There are many ways to connect peers that are supported by this function. - * To connect peers in the same topology that was created via the - * GNUNET_TESTING_create_topology, the topology variable must be set to - * GNUNET_TESTING_TOPOLOGY_NONE. If the topology variable is specified, - * a new instance of that topology will be generated and attempted to be - * connected. This could result in some connections being impossible, - * because some topologies are non-deterministic. + * 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 pg the peer group struct representing the running peers - * @param topology which topology to connect the peers in - * @param options options for connecting the topology - * @param option_modifier modifier for options that take a parameter - * @param connect_timeout how long to wait before giving up on connecting - * two peers - * @param connect_attempts how many times to attempt to connect two peers - * over the connect_timeout duration - * @param notify_callback notification to be called once all connections completed - * @param notify_cls closure for notification callback - * - * @return the number of connections that will be attempted, GNUNET_SYSERR on error + * @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 */ int -GNUNET_TESTING_connect_topology (struct GNUNET_TESTING_PeerGroup *pg, - enum GNUNET_TESTING_Topology topology, - enum GNUNET_TESTING_TopologyOption options, - double option_modifier, - struct GNUNET_TIME_Relative connect_timeout, - unsigned int connect_attempts, - GNUNET_TESTING_NotifyCompletion - notify_callback, void *notify_cls); +GNUNET_TESTING_peer_run (const char *testdir, + const char *cfgfilename, + GNUNET_TESTING_TestMain tm, + void *tm_cls); -/** - * Start or stop an individual peer from the given group. - * - * @param pg handle to the peer group - * @param offset which peer to start or stop - * @param desired_status GNUNET_YES to have it running, GNUNET_NO to stop it - * @param timeout how long to wait for shutdown - * @param cb function to call at the end - * @param cb_cls closure for cb - */ -void -GNUNET_TESTING_daemons_vary (struct GNUNET_TESTING_PeerGroup *pg, - unsigned int offset, - int desired_status, - struct GNUNET_TIME_Relative timeout, - GNUNET_TESTING_NotifyCompletion cb, - void *cb_cls); /** - * Start a peer group with a given number of peers. Notify - * on completion of peer startup and connection based on given - * topological constraints. Optionally notify on each - * established connection. + * 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'. * - * @param cfg configuration template to use - * @param total number of daemons to start - * @param timeout total time allowed for peers to start - * @param connect_cb function to call each time two daemons are connected - * @param peergroup_cb function to call once all peers are up and connected - * @param peergroup_cls closure for peergroup callbacks - * @param hostnames linked list of host structs to use to start peers on - * (NULL to run on localhost only) + * This function is useful if the testcase is for a single service + * and if that service doesn't itself depend on other services. * - * @return NULL on error, otherwise handle to control peer group + * @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 'tm' + * @return 0 on success, 1 on error */ -struct GNUNET_TESTING_PeerGroup * -GNUNET_TESTING_peergroup_start( - const struct GNUNET_CONFIGURATION_Handle *cfg, - unsigned int total, - struct GNUNET_TIME_Relative timeout, - GNUNET_TESTING_NotifyConnection connect_cb, - GNUNET_TESTING_NotifyCompletion peergroup_cb, - void *peergroup_cls, - const struct GNUNET_TESTING_Host *hostnames); +int +GNUNET_TESTING_service_run (const char *testdir, + const char *service_name, + const char *cfgfilename, + GNUNET_TESTING_TestMain tm, + void *tm_cls); + /** - * Print current topology to a graphviz readable file. + * 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. * - * @param pg a currently running peergroup to print to file - * @param output_filename the file to write the topology to - * @param notify_cb callback to call upon completion or failure - * @param notify_cb_cls closure for notify_cb + * 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 '_' */ -void -GNUNET_TESTING_peergroup_topology_to_file(struct GNUNET_TESTING_PeerGroup *pg, - const char *output_filename, - GNUNET_TESTING_NotifyCompletion notify_cb, - void *notify_cb_cls); +char * +GNUNET_TESTING_get_testname_from_underscore (const char *argv0); #if 0 /* keep Emacsens' auto-indent happy */