2 This file is part of GNUnet
3 (C) 2008, 2009, 2012 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file testing/testing.c
23 * @brief convenience API for writing testcases for GNUnet
24 * Many testcases need to start and stop a peer/service
25 * and this library is supposed to make that easier
26 * for TESTCASES. Normal programs should always
27 * use functions from gnunet_{util,arm}_lib.h. This API is
28 * ONLY for writing testcases (or internal use of the testbed).
29 * @author Christian Grothoff
33 #include "gnunet_util_lib.h"
34 #include "gnunet_testing_lib-new.h"
36 #define LOG(kind,...) \
37 GNUNET_log_from (kind, "gnunettestingnew", __VA_ARGS__)
40 * Size of a hostkey when written to a file
42 #define HOSTKEYFILESIZE 914
45 * Lowest port used for GNUnet testing. Should be high enough to not
46 * conflict with other applications running on the hosts but be low
47 * enough to not conflict with client-ports (typically starting around
50 #define LOW_PORT 12000
53 * Highest port used for GNUnet testing. Should be low enough to not
54 * conflict with the port range for "local" ports (client apps; see
55 * /proc/sys/net/ipv4/ip_local_port_range on Linux for example).
57 #define HIGH_PORT 56000
61 * Handle for a system on which GNUnet peers are executed;
62 * a system is used for reserving unique paths and ports.
64 struct GNUNET_TESTING_System
67 * Prefix (i.e. "/tmp/gnunet-testing/") we prepend to each
72 * The hostname of the controller
77 * Hostkeys data, contains "HOSTKEYFILESIZE * total_hostkeys" bytes.
82 * memory map for 'hostkeys_data'.
84 struct GNUNET_DISK_MapHandle *map;
87 * File descriptor for the map.
89 struct GNUNET_DISK_FileHandle *map_fd;
92 * Bitmap where each TCP port that has already been reserved for
93 * some GNUnet peer is recorded. Note that we additionally need to
94 * test if a port is already in use by non-GNUnet components before
95 * assigning it to a peer/service. If we detect that a port is
96 * already in use, we also mark it in this bitmap. So all the bits
97 * that are zero merely indicate ports that MIGHT be available for
100 uint32_t reserved_tcp_ports[65536 / 32];
103 * Bitmap where each UDP port that has already been reserved for
104 * some GNUnet peer is recorded. Note that we additionally need to
105 * test if a port is already in use by non-GNUnet components before
106 * assigning it to a peer/service. If we detect that a port is
107 * already in use, we also mark it in this bitmap. So all the bits
108 * that are zero merely indicate ports that MIGHT be available for
111 uint32_t reserved_udp_ports[65536 / 32];
114 * Counter we use to make service home paths unique on this system;
115 * the full path consists of the tmppath and this number. Each
116 * UNIXPATH for a peer is also modified to include the respective
117 * path counter to ensure uniqueness. This field is incremented
118 * by one for each configured peer. Even if peers are destroyed,
119 * we never re-use path counters.
121 uint32_t path_counter;
124 * The number of hostkeys
126 uint32_t total_hostkeys;
131 * Handle for a GNUnet peer controlled by testing.
133 struct GNUNET_TESTING_Peer
137 * Path to the configuration file for this peer.
142 * Binary to be executed during 'GNUNET_TESTING_peer_start'.
143 * Typically 'gnunet-service-arm' (but can be set to a
144 * specific service by 'GNUNET_TESTING_service_run' if
150 * Handle to the running binary of the service, NULL if the
151 * peer/service is currently not running.
153 struct GNUNET_OS_Process *main_process;
158 * Testing includes a number of pre-created hostkeys for faster peer
159 * startup. This function loads such keys into memory from a file.
161 * @param system the testing system handle
162 * @return GNUNET_OK on success; GNUNET_SYSERR on error
165 hostkeys_load (struct GNUNET_TESTING_System *system)
171 GNUNET_assert (NULL == system->hostkeys_data);
172 data_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
173 GNUNET_asprintf (&filename, "%s/testing_hostkeys.dat", data_dir);
174 GNUNET_free (data_dir);
176 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
178 LOG (GNUNET_ERROR_TYPE_ERROR,
179 _("Hostkeys file not found: %s\n"), filename);
180 GNUNET_free (filename);
181 return GNUNET_SYSERR;
183 /* Check hostkey file size, read entire thing into memory */
185 GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
189 GNUNET_free (filename);
190 return GNUNET_SYSERR; /* File is empty */
192 if (0 != (fs % HOSTKEYFILESIZE))
194 LOG (GNUNET_ERROR_TYPE_ERROR,
195 _("Incorrect hostkey file format: %s\n"), filename);
196 GNUNET_free (filename);
197 return GNUNET_SYSERR;
199 system->map_fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
200 GNUNET_DISK_PERM_NONE);
201 if (NULL == system->map_fd)
203 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", filename);
204 GNUNET_free (filename);
205 return GNUNET_SYSERR;
207 system->total_hostkeys = fs / HOSTKEYFILESIZE;
208 system->hostkeys_data = GNUNET_DISK_file_map (system->map_fd,
210 GNUNET_DISK_MAP_TYPE_READ,
212 GNUNET_free (filename);
218 * Function to remove the loaded hostkeys
220 * @param system the testing system handle
223 hostkeys_unload (struct GNUNET_TESTING_System *system)
225 GNUNET_break (NULL != system->hostkeys_data);
226 system->hostkeys_data = NULL;
227 GNUNET_DISK_file_unmap (system->map);
229 GNUNET_DISK_file_close (system->map_fd);
230 system->map_fd = NULL;
231 system->hostkeys_data = NULL;
232 system->total_hostkeys = 0;
237 * Create a system handle. There must only be one system
238 * handle per operating system.
240 * @param tmppath prefix path to use for all service homes
241 * @param controller hostname of the controlling host,
242 * service configurations are modified to allow
243 * control connections from this host; can be NULL
244 * @return handle to this system, NULL on error
246 struct GNUNET_TESTING_System *
247 GNUNET_TESTING_system_create (const char *tmppath,
248 const char *controller)
250 struct GNUNET_TESTING_System *system;
252 GNUNET_assert (NULL != tmppath);
253 system = GNUNET_malloc (sizeof (struct GNUNET_TESTING_System));
254 system->tmppath = GNUNET_DISK_mkdtemp (tmppath);
255 if (NULL == system->tmppath)
257 GNUNET_free (system);
260 if (NULL != controller)
261 system->controller = GNUNET_strdup (controller);
262 if (GNUNET_OK != hostkeys_load (system))
264 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
272 * Free system resources.
274 * @param system system to be freed
275 * @param remove_paths should the 'tmppath' and all subdirectories
276 * be removed (clean up on shutdown)?
279 GNUNET_TESTING_system_destroy (struct GNUNET_TESTING_System *system,
282 if (NULL != system->hostkeys_data)
283 hostkeys_unload (system);
284 if (GNUNET_YES == remove_paths)
285 GNUNET_DISK_directory_remove (system->tmppath);
286 GNUNET_free (system->tmppath);
287 GNUNET_free_non_null (system->controller);
288 GNUNET_free (system);
293 * Reserve a TCP or UDP port for a peer.
295 * @param system system to use for reservation tracking
296 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
297 * @return 0 if no free port was available
300 GNUNET_TESTING_reserve_port (struct GNUNET_TESTING_System *system,
303 struct GNUNET_NETWORK_Handle *socket;
304 struct addrinfo hint;
305 struct addrinfo *ret;
306 uint32_t *port_buckets;
315 FIXME: Instead of using getaddrinfo we should try to determine the port
316 status by the following heurestics.
318 On systems which support both IPv4 and IPv6, only ports open on both
319 address families are considered open.
320 On system with either IPv4 or IPv6. A port is considered open if it's
321 open in the respective address family
323 hint.ai_family = AF_UNSPEC; /* IPv4 and IPv6 */
324 hint.ai_socktype = (GNUNET_YES == is_tcp)? SOCK_STREAM : SOCK_DGRAM;
325 hint.ai_protocol = 0;
328 hint.ai_canonname = NULL;
330 hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV; /* Wild card address */
331 port_buckets = (GNUNET_YES == is_tcp) ?
332 system->reserved_tcp_ports : system->reserved_udp_ports;
333 for (index = (LOW_PORT / 32) + 1; index < (HIGH_PORT / 32); index++)
335 xor_image = (UINT32_MAX ^ port_buckets[index]);
336 if (0 == xor_image) /* Ports in the bucket are full */
341 if (0 == ((xor_image >> pos) & 1U))
346 open_port = (index * 32) + pos;
347 GNUNET_asprintf (&open_port_str, "%u", (unsigned int) open_port);
349 GNUNET_assert (0 == getaddrinfo (NULL, open_port_str, &hint, &ret));
350 GNUNET_free (open_port_str);
351 socket = GNUNET_NETWORK_socket_create (ret->ai_family,
352 (GNUNET_YES == is_tcp) ?
353 SOCK_STREAM : SOCK_DGRAM,
355 GNUNET_assert (NULL != socket);
356 bind_status = GNUNET_NETWORK_socket_bind (socket,
360 GNUNET_NETWORK_socket_close (socket);
362 port_buckets[index] |= (1U << pos); /* Set the port bit */
363 if (GNUNET_OK == bind_status)
365 LOG (GNUNET_ERROR_TYPE_DEBUG,
366 "Found a free port %u\n", (unsigned int) open_port);
377 * Release reservation of a TCP or UDP port for a peer
378 * (used during GNUNET_TESTING_peer_destroy).
380 * @param system system to use for reservation tracking
381 * @param is_tcp GNUNET_YES for TCP ports, GNUNET_NO for UDP
382 * @param port reserved port to release
385 GNUNET_TESTING_release_port (struct GNUNET_TESTING_System *system,
389 uint32_t *port_buckets;
393 port_buckets = (GNUNET_YES == is_tcp) ?
394 system->reserved_tcp_ports : system->reserved_udp_ports;
397 LOG (GNUNET_ERROR_TYPE_DEBUG, "Releasing port %u\n", port);
398 if (0 == (port_buckets[bucket] & (1U << pos)))
400 GNUNET_break(0); /* Port was not reserved by us using reserve_port() */
403 port_buckets[bucket] &= ~(1U << pos);
408 * Reserve a SERVICEHOME path for a peer.
410 * @param system system to use for reservation tracking
411 * @return NULL on error, otherwise fresh unique path to use
412 * as the servicehome for the peer; must be freed by the caller
416 reserve_path (struct GNUNET_TESTING_System *system)
420 GNUNET_asprintf (&reserved_path,
421 "%s/%u", system->tmppath, system->path_counter++);
422 return reserved_path;
427 * Testing includes a number of pre-created hostkeys for
428 * faster peer startup. This function can be used to
429 * access the n-th key of those pre-created hostkeys; note
430 * that these keys are ONLY useful for testing and not
431 * secure as the private keys are part of the public
432 * GNUnet source code.
434 * This is primarily a helper function used internally
435 * by 'GNUNET_TESTING_peer_configure'.
437 * @param system the testing system handle
438 * @param key_number desired pre-created hostkey to obtain
439 * @param id set to the peer's identity (hash of the public
440 * key; if NULL, GNUNET_SYSERR is returned immediately
441 * @return GNUNET_SYSERR on error (not enough keys)
444 GNUNET_TESTING_hostkey_get (const struct GNUNET_TESTING_System *system,
446 struct GNUNET_PeerIdentity *id)
448 struct GNUNET_CRYPTO_RsaPrivateKey *private_key;
449 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;
451 if ((NULL == id) || (NULL == system->hostkeys_data))
452 return GNUNET_SYSERR;
453 if (key_number >= system->total_hostkeys)
455 LOG (GNUNET_ERROR_TYPE_ERROR,
456 _("Key number %u does not exist\n"), key_number);
457 return GNUNET_SYSERR;
459 private_key = GNUNET_CRYPTO_rsa_decode_key (system->hostkeys_data +
460 (key_number * HOSTKEYFILESIZE),
462 if (NULL == private_key)
464 LOG (GNUNET_ERROR_TYPE_ERROR,
465 _("Error while decoding key %u\n"), key_number);
466 return GNUNET_SYSERR;
468 GNUNET_CRYPTO_rsa_key_get_public (private_key, &public_key);
469 GNUNET_CRYPTO_hash (&public_key,
470 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
472 GNUNET_CRYPTO_rsa_key_free (private_key);
478 * Structure for holding data to build new configurations from a configuration
484 * The system for which we are building configurations
486 struct GNUNET_TESTING_System *system;
489 * The configuration we are building
491 struct GNUNET_CONFIGURATION_Handle *cfg;
494 * The customized service home path for this peer
499 * build status - to signal error while building a configuration
506 * Function to iterate over options. Copies
507 * the options to the target configuration,
508 * updating PORT values as needed.
510 * @param cls the UpdateContext
511 * @param section name of the section
512 * @param option name of the option
513 * @param value value of the option
516 update_config (void *cls, const char *section, const char *option,
519 struct UpdateContext *uc = cls;
523 char *single_variable;
524 char *per_host_variable;
525 unsigned long long num_per_host;
528 if (GNUNET_OK != uc->status)
530 if (! ((0 == strcmp (option, "PORT"))
531 || (0 == strcmp (option, "UNIXPATH"))
532 || (0 == strcmp (option, "HOSTNAME"))))
534 GNUNET_asprintf (&single_variable, "single_%s_per_host", section);
535 GNUNET_asprintf (&per_host_variable, "num_%s_per_host", section);
536 if ((0 == strcmp (option, "PORT")) && (1 == SSCANF (value, "%u", &ival)))
540 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
543 /* FIXME: What about UDP? */
544 new_port = GNUNET_TESTING_reserve_port (uc->system, GNUNET_YES);
547 uc->status = GNUNET_SYSERR;
550 GNUNET_snprintf (cval, sizeof (cval), "%u", new_port);
553 else if ((ival != 0) &&
555 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
557 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
561 /* GNUNET_snprintf (cval, sizeof (cval), "%u", */
562 /* ival + ctx->fdnum % num_per_host); */
564 GNUNET_break (0); /* FIXME */
567 if (0 == strcmp (option, "UNIXPATH"))
570 GNUNET_CONFIGURATION_get_value_yesno (uc->cfg, "testing",
573 GNUNET_snprintf (uval, sizeof (uval), "%s/%s.sock",
574 uc->service_home, section);
577 else if ((GNUNET_YES ==
578 GNUNET_CONFIGURATION_get_value_number (uc->cfg, "testing",
583 GNUNET_break(0); /* FIXME */
586 if ((0 == strcmp (option, "HOSTNAME")) && (NULL != uc->system->controller))
588 value = uc->system->controller;
590 GNUNET_free (single_variable);
591 GNUNET_free (per_host_variable);
592 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, option, value);
597 * Section iterator to set ACCEPT_FROM in all sections
599 * @param cls the UpdateContext
600 * @param section name of the section
603 update_config_sections (void *cls,
606 struct UpdateContext *uc = cls;
607 char *orig_allowed_hosts;
611 GNUNET_CONFIGURATION_get_value_string (uc->cfg, section, "ACCEPT_FROM",
612 &orig_allowed_hosts))
614 orig_allowed_hosts = GNUNET_strdup ("127.0.0.1;");
616 if (NULL == uc->system->controller)
617 allowed_hosts = GNUNET_strdup (orig_allowed_hosts);
619 GNUNET_asprintf (&allowed_hosts, "%s%s;", orig_allowed_hosts,
620 uc->system->controller);
621 GNUNET_free (orig_allowed_hosts);
622 GNUNET_CONFIGURATION_set_value_string (uc->cfg, section, "ACCEPT_FROM",
624 GNUNET_free (allowed_hosts);
629 * Create a new configuration using the given configuration
630 * as a template; ports and paths will be modified to select
631 * available ports on the local system. If we run
632 * out of "*port" numbers, return SYSERR.
634 * This is primarily a helper function used internally
635 * by 'GNUNET_TESTING_peer_configure'.
637 * @param system system to use to coordinate resource usage
638 * @param cfg template configuration to update
639 * @return GNUNET_OK on success, GNUNET_SYSERR on error - the configuration will
640 * be incomplete and should not be used there upon
643 GNUNET_TESTING_configuration_create (struct GNUNET_TESTING_System *system,
644 struct GNUNET_CONFIGURATION_Handle *cfg)
646 struct UpdateContext uc;
647 char *default_config;
651 uc.status = GNUNET_OK;
652 GNUNET_asprintf (&uc.service_home, "%s/%u", system->tmppath,
653 system->path_counter++);
654 GNUNET_asprintf (&default_config, "%s/config", uc.service_home);
655 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG",
657 GNUNET_free (default_config);
658 GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "SERVICEHOME",
660 /* make PORTs and UNIXPATHs unique */
661 GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
662 /* allow connections to services from system controller host */
663 GNUNET_CONFIGURATION_iterate_sections (cfg, &update_config_sections, &uc);
664 /* enable loopback-based connections between peers */
665 GNUNET_CONFIGURATION_set_value_string (cfg,
667 "USE_LOCALADDR", "YES");
668 GNUNET_free (uc.service_home);
674 * Configure a GNUnet peer. GNUnet must be installed on the local
675 * system and available in the PATH.
677 * @param system system to use to coordinate resource usage
678 * @param cfg configuration to use; will be UPDATED (to reflect needed
679 * changes in port numbers and paths)
680 * @param key_number number of the hostkey to use for the peer
681 * @param id identifier for the daemon, will be set, can be NULL
682 * @param emsg set to error message (set to NULL on success), can be NULL
683 * @return handle to the peer, NULL on error
685 struct GNUNET_TESTING_Peer *
686 GNUNET_TESTING_peer_configure (struct GNUNET_TESTING_System *system,
687 struct GNUNET_CONFIGURATION_Handle *cfg,
689 struct GNUNET_PeerIdentity *id,
692 struct GNUNET_TESTING_Peer *peer;
693 struct GNUNET_DISK_FileHandle *fd;
695 char hostkey_filename[128];
696 char *config_filename;
701 if (GNUNET_OK != GNUNET_TESTING_configuration_create (system, cfg))
703 GNUNET_asprintf (&emsg_,
704 _("Failed to create configuration for peer (not enough free ports?)\n"));
705 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_);
712 if (key_number >= system->total_hostkeys)
714 GNUNET_asprintf (&emsg_,
715 _("You attempted to create a testbed with more than %u hosts. Please precompute more hostkeys first.\n"),
716 (unsigned int) system->total_hostkeys);
717 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", emsg_);
725 (GNUNET_SYSERR == GNUNET_TESTING_hostkey_get (system, key_number, id)))
727 GNUNET_asprintf (&emsg_,
728 _("Failed to initialize hostkey for peer %u\n"),
729 (unsigned int) key_number);
730 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_);
737 GNUNET_assert (GNUNET_OK ==
738 GNUNET_CONFIGURATION_get_value_string (cfg, "PATHS",
741 GNUNET_snprintf (hostkey_filename, sizeof (hostkey_filename), "%s/.hostkey",
743 GNUNET_free (service_home);
744 fd = GNUNET_DISK_file_open (hostkey_filename,
745 GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_WRITE,
746 GNUNET_DISK_PERM_USER_READ
747 | GNUNET_DISK_PERM_USER_WRITE);
753 if (HOSTKEYFILESIZE !=
754 GNUNET_DISK_file_write (fd, system->hostkeys_data
755 + (key_number * HOSTKEYFILESIZE),
758 GNUNET_asprintf (&emsg_,
759 _("Failed to write hostkey file for peer %u: %s\n"),
760 (unsigned int) key_number,
762 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_);
767 GNUNET_DISK_file_close (fd);
770 GNUNET_DISK_file_close (fd);
771 GNUNET_assert (GNUNET_OK ==
772 GNUNET_CONFIGURATION_get_value_string
773 (cfg, "PATHS", "DEFAULTCONFIG", &config_filename));
774 if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, config_filename))
776 GNUNET_asprintf (&emsg_,
777 _("Failed to write configuration file `%s' for peer %u: %s\n"),
779 (unsigned int) key_number,
781 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s", *emsg_);
786 GNUNET_free (config_filename);
789 peer = GNUNET_malloc (sizeof (struct GNUNET_TESTING_Peer));
790 peer->cfgfile = config_filename; /* Free in peer_destroy */
791 peer->main_binary = GNUNET_strdup ("gnunet-service-arm");
799 * @param peer peer to start
800 * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer already running)
803 GNUNET_TESTING_peer_start (struct GNUNET_TESTING_Peer *peer)
805 if (NULL != peer->main_process)
808 return GNUNET_SYSERR;
810 GNUNET_assert (NULL != peer->cfgfile);
811 peer->main_process = GNUNET_OS_start_process (GNUNET_YES, NULL, NULL,
817 if (NULL == peer->main_process)
819 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
820 _("Failed to start `%s': %s\n"),
823 return GNUNET_SYSERR;
832 * @param peer peer to stop
833 * @return GNUNET_OK on success, GNUNET_SYSERR on error (i.e. peer not running)
836 GNUNET_TESTING_peer_stop (struct GNUNET_TESTING_Peer *peer)
838 if (NULL == peer->main_process)
841 return GNUNET_SYSERR;
843 (void) GNUNET_OS_process_kill (peer->main_process, SIGTERM);
844 GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (peer->main_process));
845 GNUNET_OS_process_destroy (peer->main_process);
846 peer->main_process = NULL;
852 * Destroy the peer. Releases resources locked during peer configuration.
853 * If the peer is still running, it will be stopped AND a warning will be
854 * printed (users of the API should stop the peer explicitly first).
856 * @param peer peer to destroy
859 GNUNET_TESTING_peer_destroy (struct GNUNET_TESTING_Peer *peer)
861 if (NULL != peer->main_process)
864 GNUNET_TESTING_peer_stop (peer);
866 GNUNET_free (peer->cfgfile);
867 GNUNET_free (peer->main_binary);
873 * Start a single peer and run a test using the testing library.
874 * Starts a peer using the given configuration and then invokes the
875 * given callback. This function ALSO initializes the scheduler loop
876 * and should thus be called directly from "main". The testcase
877 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
879 * @param tmppath path for storing temporary data for the test
880 * also used to setup the program name for logging
881 * @param cfgfilename name of the configuration file to use;
882 * use NULL to only run with defaults
883 * @param tm main function of the testcase
884 * @param tm_cls closure for 'tm'
885 * @return 0 on success, 1 on error
888 GNUNET_TESTING_peer_run (const char *tmppath,
889 const char *cfgfilename,
890 GNUNET_TESTING_TestMain tm,
893 return GNUNET_TESTING_service_run (tmppath, "arm",
894 cfgfilename, tm, tm_cls);
899 * Structure for holding service data
901 struct ServiceContext
904 * The configuration of the peer in which the service is run
906 const struct GNUNET_CONFIGURATION_Handle *cfg;
909 * Callback to signal service startup
911 GNUNET_TESTING_TestMain tm;
914 * Closure for the above callback
921 * Callback to be called when SCHEDULER has been started
923 * @param cls the ServiceContext
924 * @param tc the TaskContext
927 service_run_main (void *cls,
928 const struct GNUNET_SCHEDULER_TaskContext *tc)
930 struct ServiceContext *sc = cls;
932 sc->tm (sc->tm_cls, sc->cfg);
937 * Start a single service (no ARM, except of course if the given
938 * service name is 'arm') and run a test using the testing library.
939 * Starts a service using the given configuration and then invokes the
940 * given callback. This function ALSO initializes the scheduler loop
941 * and should thus be called directly from "main". The testcase
942 * should self-terminate by invoking 'GNUNET_SCHEDULER_shutdown'.
944 * This function is useful if the testcase is for a single service
945 * and if that service doesn't itself depend on other services.
947 * @param tmppath path for storing temporary data for the test,
948 * also used to setup the program name for logging
949 * @param service_name name of the service to run
950 * @param cfgfilename name of the configuration file to use;
951 * use NULL to only run with defaults
952 * @param tm main function of the testcase
953 * @param tm_cls closure for 'tm'
954 * @return 0 on success, 1 on error
957 GNUNET_TESTING_service_run (const char *tmppath,
958 const char *service_name,
959 const char *cfgfilename,
960 GNUNET_TESTING_TestMain tm,
963 struct ServiceContext sc;
964 struct GNUNET_TESTING_System *system;
965 struct GNUNET_TESTING_Peer *peer;
966 struct GNUNET_CONFIGURATION_Handle *cfg;
968 GNUNET_log_setup (tmppath,
971 system = GNUNET_TESTING_system_create (tmppath, "127.0.0.1");
974 cfg = GNUNET_CONFIGURATION_create ();
975 if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfgfilename))
977 LOG (GNUNET_ERROR_TYPE_ERROR,
978 _("Failed to load configuration from %s\n"), cfgfilename);
979 GNUNET_CONFIGURATION_destroy (cfg);
980 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
983 peer = GNUNET_TESTING_peer_configure (system, cfg, 0, NULL, NULL);
986 GNUNET_CONFIGURATION_destroy (cfg);
987 hostkeys_unload (system);
988 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
991 GNUNET_free (peer->main_binary);
992 GNUNET_asprintf (&peer->main_binary, "gnunet-service-%s", service_name);
993 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer))
995 GNUNET_TESTING_peer_destroy (peer);
996 GNUNET_CONFIGURATION_destroy (cfg);
997 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1003 GNUNET_SCHEDULER_run (&service_run_main, &sc); /* Scheduler loop */
1004 if (GNUNET_OK != GNUNET_TESTING_peer_stop (peer))
1006 GNUNET_TESTING_peer_destroy (peer);
1007 GNUNET_CONFIGURATION_destroy (cfg);
1008 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1011 GNUNET_TESTING_peer_destroy (peer);
1012 GNUNET_CONFIGURATION_destroy (cfg);
1013 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1019 * Sometimes we use the binary name to determine which specific
1020 * test to run. In those cases, the string after the last "_"
1021 * in 'argv[0]' specifies a string that determines the configuration
1022 * file or plugin to use.
1024 * This function returns the respective substring, taking care
1025 * of issues such as binaries ending in '.exe' on W32.
1027 * @param argv0 the name of the binary
1028 * @return string between the last '_' and the '.exe' (or the end of the string),
1029 * NULL if argv0 has no '_'
1032 GNUNET_TESTING_get_testname_from_underscore (const char *argv0)
1034 size_t slen = strlen (argv0) + 1;
1039 memcpy (sbuf, argv0, slen);
1040 ret = strrchr (sbuf, '_');
1043 ret++; /* skip underscore */
1044 dot = strchr (ret, '.');
1047 return GNUNET_strdup (ret);
1051 /* end of testing.c */