- Remove printf, use GNUNET_log INFO
[oweals/gnunet.git] / src / include / gnunet_testing_lib.h
index 560a25355e2e404e722a30c32a5f12fc675850f8..630152ddfffd5a3e84aad1cd63b4014205d45f2d 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,7 @@
 #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"
 
 #ifdef __cplusplus
 extern "C"
 
 #ifdef __cplusplus
 extern "C"
@@ -42,316 +44,326 @@ extern "C"
 #endif
 #endif
 
 #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 GNUnet daemon (technically a set of
- * daemons; the handle is really for the master ARM
- * daemon) started by the testing library.
+ * Handle for a system on which GNUnet peers are executed;
+ * a system is used for reserving unique paths and ports.
  */
  */
-struct GNUNET_TESTING_Daemon;
+struct GNUNET_TESTING_System;
 
 
 /**
 
 
 /**
- * Prototype of a function that will be called whenever
- * a daemon was started by the testing library.
- *
- * @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;
 
 
 /**
 
 
 /**
- * Starts a GNUnet daemon.
+ * 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 sched scheduler to use 
- * @param cfg configuration to use
- * @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
- * @return handle to the daemon (actual start will be completed asynchronously)
+ * @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
  */
  */
-struct GNUNET_TESTING_Daemon *
-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 (const char *testdir,
+                             const char *trusted_ip,
+                             const char *hostname);
 
 
 /**
 
 
 /**
- * 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.  Use this function directly
+ * if multiple system objects are created for the same host
+ * (only really useful when testing --- or to make the port
+ * range configureable).
  *
  *
- * @param cls closure
- * @param 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
+ * @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
  */
  */
-typedef void (*GNUNET_TESTING_NotifyCompletion)(void *cls,
-                                               const char *emsg);
+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);
 
 
 /**
 
 
 /**
- * Stops a GNUnet daemon.
+ * Free system resources.
  *
  *
- * @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 be freed
+ * @param remove_paths should the 'testdir' and all subdirectories
+ *        be removed (clean up on shutdown)?
  */
  */
-void GNUNET_TESTING_daemon_stop (struct GNUNET_TESTING_Daemon *d,
-                                GNUNET_TESTING_NotifyCompletion cb,
-                                void * cb_cls);
+void
+GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system,
+                              int remove_paths);
 
 
 /**
 
 
 /**
- * Changes the configuration of 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.
+ *
+ * This is primarily a helper function used internally
+ * by 'GNUNET_TESTING_peer_configure'.
  *
  *
- * @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 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_reconfigure (struct GNUNET_TESTING_Daemon *d,
-                                       const struct GNUNET_CONFIGURATION_Handle *cfg,
-                                       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 timeout how long is the connection attempt
- *        allowed to take?
- * @param cb function to call at the end
- * @param cb_cls closure for cb
+ * @param system system to use 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,
-                                    struct GNUNET_TIME_Relative timeout,
-                                    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 (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.
+ * 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 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 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
  */
 void
-GNUNET_TESTING_daemons_start_va (struct GNUNET_SCHEDULER_Handle *sched,
-                                const struct GNUNET_CONFIGURATION_Handle *cfg,
-                                unsigned int total,
-                                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'.
  *
  *
- * @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
+ * 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_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 */
 {
 
 #if 0                           /* keep Emacsens' auto-indent happy */
 {