- Remove printf, use GNUNET_log INFO
[oweals/gnunet.git] / src / include / gnunet_testing_lib.h
index 459e433148f32e8b70045b911d6d1d804db97a30..630152ddfffd5a3e84aad1cd63b4014205d45f2d 100644 (file)
@@ -1,10 +1,10 @@
 /*
       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
-      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
 
 /**
  * @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
  */
 
@@ -33,6 +34,7 @@
 #define GNUNET_TESTING_LIB_H
 
 #include "gnunet_util_lib.h"
+#include "gnunet_statistics_service.h"
 
 #ifdef __cplusplus
 extern "C"
@@ -42,297 +44,326 @@ extern "C"
 #endif
 #endif
 
+/**
+ * Size of each hostkey in the hostkey file (in BYTES).  This is the
+ * maximum length of the S-expressions generated by libgcrypt for the
+ * curves (rounded up to the next full KB to make IO nicer); it is NOT
+ * the number of bits in the key.
+ */
+#define GNUNET_TESTING_HOSTKEYFILESIZE 1024
+
+/**
+ * Handle for a system on which GNUnet peers are executed;
+ * a system is used for reserving unique paths and ports.
+ */
+struct GNUNET_TESTING_System;
 
 
 /**
- * Handle for a GNUnet daemon (technically a set of
- * daemons; the handle is really for the master ARM
- * daemon) started by the testing library.
+ * Handle for a GNUnet peer controlled by testing.
  */
-struct GNUNET_TESTING_Daemon;
+struct GNUNET_TESTING_Peer;
 
 
 /**
- * Prototype of a function that will be called whenever
- * a daemon was started by 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 id identifier for the daemon, NULL on error
- * @param d handle to the daemon, NULL if starting the daemon failed
+ * @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 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
+ * @return handle to this system, NULL on error
  */
-typedef void (*GNUNET_TESTING_NotifyDaemonRunning)(void *cls,
-                                                  const struct GNUNET_PeerIdentity *id,
-                                                  struct GNUNET_TESTING_Daemon *d);
+struct GNUNET_TESTING_System *
+GNUNET_TESTING_system_create (const char *testdir,
+                             const char *trusted_ip,
+                             const char *hostname);
 
 
 /**
- * Starts 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 service_home directory to use as the service home directory
- * @param transports transport services that should be loaded
- * @param applications application services and daemons that should be started
- * @param port_offset offset to add to all ports for all services
- * @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
+ * @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 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 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_start (struct GNUNET_SCHEDULER_Handle *sched,
-                            struct GNUNET_CONFIGURATION_Handle *cfg,
-                            const char *service_home,
-                            const char *transports,
-                            const char *applications,
-                            uint16_t port_offset,
-                            const char *hostname,
-                            GNUNET_TESTING_NotifyDaemonRunning cb,
-                            void *cb_cls);
+struct GNUNET_TESTING_System *
+GNUNET_TESTING_system_create_with_portrange (const char *testdir,
+                                            const char *trusted_ip,
+                                            const char *hostname,
+                                            uint16_t lowport,
+                                            uint16_t highport);
 
 
 /**
- * Prototype of a function that will be called when a
- * particular operation was completed the testing library.
+ * Free system resources.
  *
- * @param cls closure
- * @param success GNUNET_YES on success
+ * @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_NotifyCompletion)(void *cls,
-                                               int success);
+void
+GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system,
+                              int remove_paths);
 
 
 /**
- * Stops a GNUnet daemon.
+ * 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 d the daemon that should be stopped
- * @param cb function called once the daemon was stopped
- * @param cb_cls closure for cb
+ * 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)
  */
-void GNUNET_TESTING_daemon_stop (struct GNUNET_TESTING_Daemon *d,
-                                GNUNET_TESTING_NotifyCompletion cb,
-                                void * cb_cls);
-
+struct GNUNET_CRYPTO_EccPrivateKey *
+GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system,
+                           uint32_t key_number,
+                           struct GNUNET_PeerIdentity *id);
 
 
 /**
- * Establish a connection between two GNUnet daemons.
+ * Reserve a TCP or UDP port for a peer.
  *
- * @param d1 handle for the first daemon
- * @param d2 handle for the second daemon
- * @param cb function to call at the end
- * @param cb_cls closure for cb
+ * @param system system to use for reservation tracking
+ * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
+ * @return 0 if no free port was available
  */
-void GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1,
-                                    struct GNUNET_TESTING_Daemon *d2,
-                                    GNUNET_TESTING_NotifyCompletion cb,
-                                    void *cb_cls);
-
+uint16_t 
+GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system,
+                            int is_tcp);
 
 
 /**
- * Start count gnunetd processes with the same set of
- * transports and applications.  The port numbers will
- * be computed by adding delta each time (zero
- * times for the first peer).
+ * Release reservation of a TCP or UDP port for a peer
+ * (used during GNUNET_TESTING_peer_destroy).
  *
- * @param total number of daemons to start
- * @param service_home_prefix path to use as the prefix for the home of the services
- * @param transports which transports should all peers use
- * @param applications which applications should be used?
- * @param timeout how long is this allowed to take?
- * @param cb function to call on each daemon that was started
- * @param cb_cls closure for cb
- * @param cbe function to call at the end
- * @param cbe_cls closure for cbe
- * @param hostname where to run the peers; can be NULL (to run
- *        everything on localhost).
- * @param va Additional hosts can be specified using a NULL-terminated list of
- *        varargs, hosts will then be used round-robin from that
- *        list; va only contains anything if hostname != NULL.
+ * @param system system to use for reservation tracking
+ * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
+ * @param port reserved port to release
  */
 void
-GNUNET_TESTING_daemons_start_Va (struct GNUNET_SCHEDULER_Handle *sched,
-                                struct GNUNET_CONFIGURATION_Handle *cfg,
-                                unsigned int total,
-                                const char *service_home_prefix,
-                                const char *transports,
-                                const char *applications,
-                                GNUNET_TESTING_NotifyDaemonRunning cb,
-                                void *cb_cls,
-                                GNUNET_TESTING_NotifyCompletion cbe,
-                                void *cbe_cls,
-                                const char *hostname,
-                                va_list va);
+GNUNET_TESTING_release_port (struct GNUNET_TESTING_System *system,
+                            int is_tcp,
+                            uint16_t port);
+
 
 /**
- * Start count gnunetd processes with the same set of
- * transports and applications.  The port numbers will
- * be computed by adding delta each time (zero
- * times for the first peer).
+ * Create a new configuration using the given configuration as a template;
+ * ports and paths will be modified to select available ports on the local
+ * system. The default configuration will be available in PATHS section under
+ * the option DEFAULTCONFIG after the call. SERVICE_HOME is also set in PATHS
+ * section to the temporary directory specific to this configuration. If we run
+ * out of "*port" numbers, return SYSERR.
+ *
+ * This is primarily a helper function used internally
+ * by 'GNUNET_TESTING_peer_configure'.
  *
- * @param total number of daemons to start
- * @param service_home_prefix path to use as the prefix for the home of the services
- * @param transports which transports should all peers use
- * @param applications which applications should be used?
- * @param timeout how long is this allowed to take?
- * @param cb function to call on each daemon that was started
- * @param cb_cls closure for cb
- * @param cbe function to call at the end
- * @param cbe_cls closure for cbe
- * @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.
+ * @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_daemons_start (struct GNUNET_SCHEDULER_Handle *sched,
-                             struct GNUNET_CONFIGURATION_Handle *cfg,
-                             unsigned int total,
-                             const char *service_home_prefix,
-                             const char *transports,
-                             const char *applications,
-                             GNUNET_TESTING_NotifyDaemonRunning cb,
-                             void *cb_cls,
-                             GNUNET_TESTING_NotifyCompletion cbe,
-                             void *cbe_cls,
-                             const char *hostname,
-                             ...);
+int
+GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system,
+                                    struct GNUNET_CONFIGURATION_Handle *cfg);
+// FIXME: add dual to 'release' ports again...
 
 
 /**
- * Handle to an entire testbed of GNUnet peers.
+ * Configure a GNUnet peer.  GNUnet must be installed on the local
+ * system and available in the PATH. 
+ *
+ * @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_Testbed;
+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);
+
 
 /**
- * Prototype of a function that will be called when 
- * a testbed is being created.
+ * Obtain the peer identity from a peer handle.
  *
- * @param cls closure
- * @param tb NULL on error
+ * @param peer peer handle for which we want the peer's identity
+ * @param id identifier for the daemon, will be set
  */
-typedef void (*GNUNET_TESTING_NotifyTestbedRunning)(void *cls,
-                                                   struct GNUNET_TESTING_Testbed *tb);
+void
+GNUNET_TESTING_peer_get_identity (struct GNUNET_TESTING_Peer *peer,
+                                 struct GNUNET_PeerIdentity *id);
 
 
 /**
- * Topologies supported for testbeds.
+ * Start the peer. 
+ *
+ * @param peer peer to start
+ * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer already running)
  */
-enum GNUNET_TESTING_Topology
-{
-  /**
-   * A clique (everyone connected to everyone else).
-   */
-  GNUNET_TESTING_TOPOLOGY_CLIQUE,
+int
+GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer);
 
-  /**
-   * Small-world network (2d torus plus random links).
-   */
-  GNUNET_TESTING_TOPOLOGY_SMALL_WORLD,
 
-  /**
-   * Ring topology.
-   */
-  GNUNET_TESTING_TOPOLOGY_RING,
+/**
+ * Stop the peer. 
+ *
+ * @param peer peer to stop
+ * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer not running)
+ */
+int
+GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer);
 
-  /**
-   * 2-d torus.
-   */
-  GNUNET_TESTING_TOPOLOGY_2D_TORUS,
 
-  /**
-   * Random graph.
-   */
-  GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI,
+/**
+ * Destroy the peer.  Releases resources locked during peer configuration.
+ * If the peer is still running, it will be stopped AND a warning will be
+ * printed (users of the API should stop the peer explicitly first).
+ *
+ * @param peer peer to destroy
+ */
+void
+GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer);
 
-  /**
-   * All peers are disconnected.
-   */
-  GNUNET_TESTING_TOPOLOGY_NONE
-};
 
+/**
+ * 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);
 
 
 /**
- * Start count GNUnet daemons with a particular
- * topology.
+ * Waits for a peer to terminate. The peer's main process will also be destroyed.
  *
- * @param size number of peers the testbed should have
- * @param topology desired topology (enforced via F2F)
- * @param service_home_prefix path to use as the prefix for the home of the services
- * @param transports which transports should all peers use
- * @param applications which applications should be used?
- * @param timeout how long is this allowed to take?
- * @param cb function to call on each daemon that was started
- * @param cb_cls closure for cb
- * @param cte function to call at the end
- * @param cte_cls closure for cbe
- * @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.
+ * @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
  */
-void
-GNUNET_TESTING_testbed_start (struct GNUNET_SCHEDULER_Handle *sched,
-                             struct GNUNET_CONFIGURATION_Handle *cfg,
-                             unsigned int size,
-                             enum GNUNET_TESTING_Topology topology,
-                             const char *service_home_prefix,
-                             const char *transports,
-                             const char *applications,
-                             GNUNET_TESTING_NotifyDaemonRunning cb,
-                             void *cb_cls,
-                             GNUNET_TESTING_NotifyTestbedRunning cte,
-                             void *cte_cls,
-                             const char *hostname,
-                             ...);
+int
+GNUNET_TESTING_peer_wait (struct GNUNET_TESTING_Peer *peer);
 
 
+/**
+ * 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);
 
 
 /**
- * Stop all of the daemons started with the start function.
+ * Start a single peer and run a test using the testing library.
+ * Starts a peer using the given configuration and then invokes the
+ * given callback.  This function ALSO initializes the scheduler loop
+ * and should thus be called directly from "main".  The testcase
+ * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
  *
- * @param tb handle for the testbed
- * @param cb function to call at the end
- * @param cb_cls closure for cb
+ * @param testdir only the directory name without any path. This is used for
+ *          all service homes; the directory will be created in a temporary
+ *          location depending on the underlying OS
+ * @param cfgfilename name of the configuration file to use;
+ *         use NULL to only run with defaults
+ * @param tm main function of the testcase
+ * @param tm_cls closure for 'tm'
+ * @return 0 on success, 1 on error
  */
-void
-GNUNET_TESTING_testbed_stop (struct GNUNET_TESTING_Testbed *tb,
-                            GNUNET_TESTING_NotifyCompletion cb,
-                            void *cb_cls );
-
+int
+GNUNET_TESTING_peer_run (const char *testdir,
+                        const char *cfgfilename,
+                        GNUNET_TESTING_TestMain tm,
+                        void *tm_cls);
 
 
 /**
- * Simulate churn in the testbed by stopping some peers (and possibly
- * re-starting others if churn is called multiple times).  This
- * function can only be used to create leave-join churn (peers "never"
- * leave for good).  First "voff" random peers that are currently
- * online will be taken offline; then "von" random peers that are then
- * offline will be put back online.  No notifications will be
- * generated for any of these operations except for the callback upon
- * completion.  Note that the implementation is at liberty to keep
- * the ARM service itself (but none of the other services or daemons)
- * running even though the "peer" is being varied offline.
+ * Start a single service (no ARM, except of course if the given
+ * service name is 'arm') and run a test using the testing library.
+ * Starts a service using the given configuration and then invokes the
+ * given callback.  This function ALSO initializes the scheduler loop
+ * and should thus be called directly from "main".  The testcase
+ * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
+ *
+ * This function is useful if the testcase is for a single service
+ * and if that service doesn't itself depend on other services.
  *
- * @param tb handle for the testbed
- * @param voff number of peers that should go offline
- * @param von number of peers that should come back online;
- *            must be zero on first call (since "testbed_start"
- *            always starts all of the peers)
- * @param cb function to call at the end
- * @param cb_cls closure for cb
+ * @param testdir only the directory name without any path. This is used for
+ *          all service homes; the directory will be created in a temporary
+ *          location depending on the underlying OS
+ * @param service_name name of the service to run
+ * @param cfgfilename name of the configuration file to use;
+ *         use NULL to only run with defaults
+ * @param tm main function of the testcase
+ * @param tm_cls closure for 'tm'
+ * @return 0 on success, 1 on error
  */
-void
-GNUNET_TESTING_testbed_churn (struct GNUNET_TESTING_Testbed *tb,
-                             unsigned int voff,
-                             unsigned int von,
-                             GNUNET_TESTING_NotifyCompletion cb,
-                             void *cb_cls);
+int
+GNUNET_TESTING_service_run (const char *testdir,
+                           const char *service_name,
+                           const char *cfgfilename,
+                           GNUNET_TESTING_TestMain tm,
+                           void *tm_cls);
 
 
+/**
+ * Sometimes we use the binary name to determine which specific
+ * test to run.  In those cases, the string after the last "_"
+ * in 'argv[0]' specifies a string that determines the configuration
+ * file or plugin to use.  
+ *
+ * This function returns the respective substring, taking care
+ * of issues such as binaries ending in '.exe' on W32.
+ *
+ * @param argv0 the name of the binary
+ * @return string between the last '_' and the '.exe' (or the end of the string),
+ *         NULL if argv0 has no '_' 
+ */
+char *
+GNUNET_TESTING_get_testname_from_underscore (const char *argv0);
+
 
 #if 0                           /* keep Emacsens' auto-indent happy */
 {