- doc
[oweals/gnunet.git] / src / include / gnunet_testing_lib.h
index 3047319e4c6ff324e807cb2931ac876e8449fd20..c15116876f3496d44fe460b54aecaff3340dde63 100644 (file)
@@ -1,10 +1,10 @@
 /*
       This file is part of GNUnet
 /*
       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
 
       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
       option) any later version.
 
       GNUnet is distributed in the hope that it will be useful, but
 
 /**
  * @file include/gnunet_testing_lib.h
 
 /**
  * @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
  */
 
  * @author Christian Grothoff
  */
 
@@ -33,6 +34,8 @@
 #define GNUNET_TESTING_LIB_H
 
 #include "gnunet_util_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"
 
 #ifdef __cplusplus
 extern "C"
@@ -42,486 +45,400 @@ extern "C"
 #endif
 #endif
 
 #endif
 #endif
 
-/* Forward declaration */
-struct GNUNET_TESTING_Daemon;
-/* Forward declaration */
-struct GNUNET_TESTING_PeerGroup;
+/**
+ * Size of each hostkey in the hostkey file (in BYTES).
+ */
+#define GNUNET_TESTING_HOSTKEYFILESIZE sizeof (struct GNUNET_CRYPTO_EccPrivateKey)
 
 /**
 
 /**
- * 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 system on which GNUnet peers are executed;
+ * a system is used for reserving unique paths and ports.
  */
  */
-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;
 
 
 /**
 
 
 /**
- * Prototype of a function that will be called whenever
- * two daemons are connected by the testing library.
- *
- * @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)
+ * Handle for a GNUnet peer controlled by testing.
  */
  */
-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_Peer;
+
 
 /**
 
 /**
- * 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 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)
+ * Specification of a service that is to be shared among peers
  */
  */
-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_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;
+};
 
 
-struct GNUNET_TESTING_Daemon *
-GNUNET_TESTING_daemon_get (struct GNUNET_TESTING_PeerGroup *pg, unsigned int position);
 
 /**
 
 /**
- * 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);
 
 
 /**
 
 
 /**
- * Stops a GNUnet daemon.
+ * 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 d the daemon that should be stopped
- * @param cb function called once the daemon was stopped
- * @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.  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
  */
  */
-void GNUNET_TESTING_daemon_stop (struct GNUNET_TESTING_Daemon *d,
-                                GNUNET_TESTING_NotifyCompletion cb,
-                                void * cb_cls);
+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);
 
 
 /**
 
 
 /**
- * Changes the configuration of a GNUnet daemon.
+ * Free system resources.
  *
  *
- * @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 be freed
+ * @param remove_paths should the 'testdir' and all subdirectories
+ *        be removed (clean up on shutdown)?
  */
  */
-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_system_destroy (struct GNUNET_TESTING_System *system,
+                              int remove_paths);
 
 
-#if HIDDEN
-/*
- * Get the short name of a running peer
+
+/**
+ * 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 d the daemon handle
+ * @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)
  */
  */
-char *
-GNUNET_TESTING_daemon_get_shortname(struct GNUNET_TESTING_Daemon *d);
+struct GNUNET_CRYPTO_EccPrivateKey *
+GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system,
+                           uint32_t key_number,
+                           struct GNUNET_PeerIdentity *id);
 
 
-char *
-GNUNET_TESTING_daemon_get_hostname (struct GNUNET_TESTING_Daemon *d);
 
 
-char *
-GNUNET_TESTING_daemon_get_username (struct GNUNET_TESTING_Daemon *d);
-
-struct GNUNET_PeerIdentity *
-GNUNET_TESTING_daemon_get_peer (struct GNUNET_TESTING_Daemon *d);
+/**
+ * Reserve a port for a peer.
+ *
+ * @param system system to use for reservation tracking
+ * @return 0 if no free port was available
+ */
+uint16_t
+GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system);
 
 
-struct GNUNET_CONFIGURATION_Handle *
-GNUNET_TESTING_daemon_get_config (struct GNUNET_TESTING_Daemon *d);
-#endif
 
 /**
 
 /**
- * Establish a connection between two GNUnet daemons.
+ * Release reservation of a TCP or UDP port for a peer
+ * (used during GNUNET_TESTING_peer_destroy).
  *
  *
- * @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 system system to use for reservation tracking
+ * @param port reserved port to release
  */
  */
-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_release_port (struct GNUNET_TESTING_System *system,
+                            uint16_t port);
 
 
 /**
 
 
 /**
- * Handle to a group of GNUnet peers.
+ * 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 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_PeerGroup;
+int
+GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system,
+                                    struct GNUNET_CONFIGURATION_Handle *cfg);
+// FIXME: add dual to 'release' ports again...
 
 
 /**
 
 
 /**
- * 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.
+ * Configure a GNUnet peer.  GNUnet must be installed on the local
+ * system and available in the PATH.
  *
  *
- * @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 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
  */
  */
-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);
+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);
 
 
 /**
 
 
 /**
- * Shutdown all peers started in the given group.
+ * Obtain the peer identity from a peer handle.
  *
  *
- * @param pg handle to the peer group
+ * @param peer peer handle for which we want the peer's identity
+ * @param id identifier for the daemon, will be set
  */
 void
  */
 void
-GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg);
-
-int
-GNUNET_TESTING_create_topology (struct GNUNET_TESTING_PeerGroup *pg);
+GNUNET_TESTING_peer_get_identity (struct GNUNET_TESTING_Peer *peer,
+                                 struct GNUNET_PeerIdentity *id);
 
 
 /**
 
 
 /**
- * Handle to an entire testbed 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_Testbed;
+int
+GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer);
+
 
 /**
 
 /**
- * Phases of starting GNUnet on a system.
+ * 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 peer peer to stop
+ * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer not running)
  */
  */
-enum StartPhase
-{
-    /**
-     * Copy the configuration file to the target system.
-     */
-  SP_COPYING,
-
-    /**
-     * Configuration file has been copied, start ARM on target system.
-     */
-  SP_COPIED,
-
-    /**
-     * 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,
-
-    /**
-     * 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
-};
+int
+GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer);
 
 
 /**
 
 
 /**
- * Handle for a GNUnet daemon (technically a set of
- * daemons; the handle is really for the master ARM
- * daemon) started by the testing library.
+ * 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
  */
  */
-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;
+void
+GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer);
 
 
-  /**
-   * In which phase are we during the start of
-   * this process?
-   */
-  enum StartPhase phase;
 
 
-  /**
-   * ID of the current task.
-   */
-  GNUNET_SCHEDULER_TaskIdentifier task;
+/**
+ * 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
+ */
+int
+GNUNET_TESTING_peer_kill (struct GNUNET_TESTING_Peer *peer);
 
 
-  /**
-   * Handle to the server.
-   */
-  struct GNUNET_CORE_Handle *server;
 
 
-  /**
-   * Handle to the transport service of this peer
-   */
-  struct GNUNET_TRANSPORT_Handle *th;
+/**
+ * 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);
 
 
-  /**
-   * HELLO message for this peer
-   */
-  struct GNUNET_HELLO_Message *hello;
-};
 
 /**
 
 /**
- * Topologies supported for testbeds.
+ * 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
  */
  */
-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,
+typedef void (*GNUNET_TESTING_PeerStopCallback) (void *cls,
+                                                 struct GNUNET_TESTING_Peer *
+                                                 peer,
+                                                 int success);
 
 
-  /**
-   * Small-world network (ring plus random links).
-   */
-  GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING,
 
 
-  /**
-   * Ring topology.
-   */
-  GNUNET_TESTING_TOPOLOGY_RING,
+/**
+ * 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);
 
 
-  /**
-   * 2-d torus.
-   */
-  GNUNET_TESTING_TOPOLOGY_2D_TORUS,
 
 
-  /**
-   * Random graph.
-   */
-  GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI,
+/**
+ * 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);
 
 
-  /**
-   * Certain percentage of peers are unable to communicate directly
-   * replicating NAT conditions
-   */
-  GNUNET_TESTING_TOPOLOGY_INTERNAT,
 
 
-  /**
-   * All peers are disconnected.
-   */
-  GNUNET_TESTING_TOPOLOGY_NONE
-};
+/**
+ * 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
+ */
+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'.
  *
  *
- * @param tb handle for the testbed
- * @param cb function to call when done
- * @param cb_cls closure for cb
+ * This function is useful if the testcase is for a single service
+ * and if that service doesn't itself depend on other services.
+ *
+ * @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
  */
  */
-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 */
 
 
 #if 0                           /* keep Emacsens' auto-indent happy */