glitch in the license text detected by hyazinthe, thank you!
[oweals/gnunet.git] / src / include / gnunet_testing_lib.h
index 3d36207bd7c1ed8d2e5e9ffe4632626c9dc0309e..a8ee2a9604bc994ba7ccd7b376934d5a4d9e7e58 100644 (file)
@@ -1,38 +1,44 @@
 /*
       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
-      option) any later version.
+      GNUnet is free software: you can redistribute it and/or modify it
+      under the terms of the GNU Affero General Public License as published
+      by the Free Software Foundation, either version 3 of the License,
+      or (at your option) any later version.
 
       GNUnet is distributed in the hope that it will be useful, but
       WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-      General Public License for more details.
-
-      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.
+      Affero General Public License for more details.
  */
 
 /**
- * @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"
@@ -43,483 +49,408 @@ extern "C"
 #endif
 
 /**
- * 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_EddsaPrivateKey)
 
 /**
- * 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)
+ * The environmental variable, if set, that dictates where testing should place
+ * generated peer configurations
  */
-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);
+#define GNUNET_TESTING_PREFIX "GNUNET_TESTING_PREFIX"
 
 
 /**
- * Handle to an entire testbed of GNUnet peers.
+ * Handle for a system on which GNUnet peers are executed;
+ * a system is used for reserving unique paths and ports.
  */
-struct GNUNET_TESTING_Testbed;
+struct GNUNET_TESTING_System;
+
 
 /**
- * Phases of starting GNUnet on a system.
+ * Handle for a GNUnet peer controlled by testing.
  */
-enum GNUNET_TESTING_StartPhase
-{
-  /**
-   * Copy the configuration file to the target system.
-   */
-  SP_COPYING,
-
-  /**
-   * Configuration file has been copied, start ARM on target system.
-   */
-  SP_COPIED,
+struct GNUNET_TESTING_Peer;
 
-  /**
-   * 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).
-   */
-  SP_START_ARMING,
-
-  /**
-   * We're waiting for CORE to start.
-   */
-  SP_START_CORE,
 
+/**
+ * Specification of a service that is to be shared among peers
+ */
+struct GNUNET_TESTING_SharedService
+{
   /**
-   * 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.
+   * The name of the service.
    */
-  SP_START_DONE,
+  const char *service;
 
   /**
-   * 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.
+   * The configuration template for the service.  Cannot be NULL
    */
-  SP_SHUTDOWN_START,
+  const struct GNUNET_CONFIGURATION_Handle *cfg;
 
   /**
-   * 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).
+   * The number of peers which share an instance of the service.  0 for sharing
+   * among all peers
    */
-  SP_CONFIG_UPDATE
+  unsigned int share;
 };
 
+
 /**
- * Prototype of a function that will be called when a
- * particular operation was completed the testing library.
+ * 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 emsg 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_NotifyCompletion)(void *cls,
-                                                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);
+
 
 /**
- * Handle for a GNUnet daemon (technically a set of
- * daemons; the handle is really for the master ARM
- * daemon) started 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 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_Daemon
-{
-  /**
-   * Our scheduler.
-   */
-  struct GNUNET_SCHEDULER_Handle *sched;
-
-  /**
-   * Our configuration.
-   */
-  struct GNUNET_CONFIGURATION_Handle *cfg;
-
-  /**
-   * Host to run GNUnet on.
-   */
-  char *hostname;
-
-  /**
-   * Result of GNUNET_i2s of this peer,
-   * for printing
-   */
-  char *shortname;
-
-  /**
-   * Username we are using.
-   */
-  char *username;
-
-  /**
-   * Name of the configuration file
-   */
-  char *cfgfile;
-
-  /**
-   * 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;
-
-  /**
-   * PID of the process that we started last.
-   */
-  pid_t pid;
-
-  /**
-   * How many iterations have we been waiting for
-   * the started process to complete?
-   */
-  unsigned int wait_runs;
-
-  /**
-   * In which phase are we during the start of
-   * this process?
-   */
-  enum GNUNET_TESTING_StartPhase phase;
+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);
 
-  /**
-   * 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;
 
-  /**
-   * Set to GNUNET_YES once the peer is up.
-   */
-  int running;
-};
+/**
+ * Free system resources.
+ *
+ * @param system system to be freed
+ * @param remove_paths should the 'testdir' and all subdirectories
+ *        be removed (clean up on shutdown)?
+ */
+void
+GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system,
+                              int remove_paths);
 
 
 /**
- * Handle to a group of GNUnet peers.
+ * 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.
+ *
+ * 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)
  */
-struct GNUNET_TESTING_PeerGroup;
+struct GNUNET_CRYPTO_EddsaPrivateKey *
+GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system,
+                           uint32_t key_number,
+                           struct GNUNET_PeerIdentity *id);
 
 
 /**
- * Prototype of a function that will be called whenever
- * two daemons are connected by the testing library.
+ * Reserve a port for a peer.
  *
- * @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 system system to use for reservation tracking
+ * @return 0 if no free port was available
  */
-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);
+uint16_t
+GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system);
+
 
 /**
- * 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.
+ * Release reservation of a TCP or UDP port for a peer
+ * (used during GNUNET_TESTING_peer_destroy).
  *
- * @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 use for reservation tracking
+ * @param port reserved port to release
  */
-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);
-
-struct GNUNET_TESTING_Daemon *
-GNUNET_TESTING_daemon_get (struct GNUNET_TESTING_PeerGroup *pg, unsigned int position);
+void
+GNUNET_TESTING_release_port (struct GNUNET_TESTING_System *system,
+                            uint16_t port);
 
 
 /**
- * Stops a GNUnet daemon.
+ * 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 #GNUNET_SYSERR.
+ *
+ * This is primarily a helper function used internally
+ * by #GNUNET_TESTING_peer_configure().
  *
- * @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 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
  */
-void GNUNET_TESTING_daemon_stop (struct GNUNET_TESTING_Daemon *d,
-                                GNUNET_TESTING_NotifyCompletion cb,
-                                void * cb_cls);
+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 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,
-                                    GNUNET_TESTING_NotifyConnection cb,
-                                    void *cb_cls);
+void
+GNUNET_TESTING_peer_get_identity (struct GNUNET_TESTING_Peer *peer,
+                                 struct GNUNET_PeerIdentity *id);
 
 
+/**
+ * Start the peer.
+ *
+ * @param peer peer to start
+ * @return #GNUNET_OK on success,
+ *         #GNUNET_SYSERR on error (i.e. peer already running)
+ */
+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.
+ * 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 peer peer to destroy
  */
 void
-GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg);
+GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer);
 
 
 /**
- * Topologies supported for testbeds.
+ * 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
  */
-enum GNUNET_TESTING_Topology
-{
-  /**
-   * A clique (everyone connected to everyone else).
-   */
-  GNUNET_TESTING_TOPOLOGY_CLIQUE,
+int
+GNUNET_TESTING_peer_kill (struct GNUNET_TESTING_Peer *peer);
 
-  /**
-   * 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,
+/**
+ * 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
+ */
+int
+GNUNET_TESTING_peer_wait (struct GNUNET_TESTING_Peer *peer);
 
-  /**
-   * Ring topology.
-   */
-  GNUNET_TESTING_TOPOLOGY_RING,
 
-  /**
-   * 2-d torus.
-   */
-  GNUNET_TESTING_TOPOLOGY_2D_TORUS,
+/**
+ * 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);
 
-  /**
-   * Random graph.
-   */
-  GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI,
 
-  /**
-   * Certain percentage of peers are unable to communicate directly
-   * replicating NAT conditions
-   */
-  GNUNET_TESTING_TOPOLOGY_INTERNAT,
+/**
+ * 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 @a cb
+ * @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);
 
-  /**
-   * FIXME: implement
-   */
-  GNUNET_TESTING_TOPOLOGY_SCALE_FREE,
 
-  /**
-   * 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);
 
 
 /**
- * FIXME: document
+ * Signature of the 'main' function for a (single-peer) testcase that
+ * is run using #GNUNET_TESTING_peer_run().
+ *
+ * @param cls closure
+ * @param cfg configuration of the peer that was started
+ * @param peer identity of the peer that was created
  */
-int
-GNUNET_TESTING_create_topology (struct GNUNET_TESTING_PeerGroup *pg
-                               /* enum GNUNET_TESTING_Topology topo */);
+typedef void
+(*GNUNET_TESTING_TestMain) (void *cls,
+                            const struct GNUNET_CONFIGURATION_Handle *cfg,
+                            struct GNUNET_TESTING_Peer *peer);
 
 
 /**
- * Start "count" GNUnet daemons with a particular topology.
+ * 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 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 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
  */
-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,
-                             ...);
+int
+GNUNET_TESTING_peer_run (const char *testdir,
+                        const char *cfgfilename,
+                        GNUNET_TESTING_TestMain tm,
+                        void *tm_cls);
 
 
 /**
- * Stop all of the daemons started with the start function.
+ * 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 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 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_stop (struct GNUNET_TESTING_Testbed *tb,
-                            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);
 
 
 /**
- * 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.
+ * 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 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 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_testbed_churn (struct GNUNET_TESTING_Testbed *tb,
-                             unsigned int voff,
-                             unsigned int von,
-                             GNUNET_TESTING_NotifyCompletion cb,
-                             void *cb_cls);
+char *
+GNUNET_TESTING_get_testname_from_underscore (const char *argv0);
 
 
 #if 0                           /* keep Emacsens' auto-indent happy */
@@ -530,3 +461,5 @@ GNUNET_TESTING_testbed_churn (struct GNUNET_TESTING_Testbed *tb,
 #endif
 
 #endif
+
+/** @} */  /* end of group */