aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2012-06-12 22:26:07 +0000
committerFlorian Dold <florian.dold@gmail.com>2012-06-12 22:26:07 +0000
commitb441997d46bfa7e722dc2cd939f79890ff6ca8fd (patch)
treee2a7ed44ba8bd8d3b1570c2feed7d96ff1676048 /src
parent1489edfdd05db78cbe2d66be4d274e7f69af48b0 (diff)
downloadgnunet-b441997d46bfa7e722dc2cd939f79890ff6ca8fd.tar.gz
gnunet-b441997d46bfa7e722dc2cd939f79890ff6ca8fd.zip
added a command line tool for running and controlling services for testing
Diffstat (limited to 'src')
-rw-r--r--src/include/gnunet_testing_lib-new.h26
-rw-r--r--src/testing/Makefile.am13
-rw-r--r--src/testing/gnunet-testing-run-service.c187
-rw-r--r--src/testing/testing.c113
4 files changed, 338 insertions, 1 deletions
diff --git a/src/include/gnunet_testing_lib-new.h b/src/include/gnunet_testing_lib-new.h
index c3d17c48d..fb51d2fb7 100644
--- a/src/include/gnunet_testing_lib-new.h
+++ b/src/include/gnunet_testing_lib-new.h
@@ -219,6 +219,18 @@ typedef void (*GNUNET_TESTING_TestMain)(void *cls,
219 219
220 220
221/** 221/**
222 * Signature of the 'main' function for a (single-peer) testcase that
223 * is run using 'GNUNET_TESTING_system_run_restartable'.
224 *
225 * @param cls closure
226 * @param cfg configuration of the peer that was started
227 */
228typedef void (*GNUNET_TESTING_RestartableTestMain)(void *cls,
229 const struct GNUNET_CONFIGURATION_Handle *cfg,
230 const struct GNUNET_TESTING_Peer *peer);
231
232
233/**
222 * Start a single peer and run a test using the testing library. 234 * Start a single peer and run a test using the testing library.
223 * Starts a peer using the given configuration and then invokes the 235 * Starts a peer using the given configuration and then invokes the
224 * given callback. This function ALSO initializes the scheduler loop 236 * given callback. This function ALSO initializes the scheduler loop
@@ -270,6 +282,20 @@ GNUNET_TESTING_service_run (const char *testdir,
270 void *tm_cls); 282 void *tm_cls);
271 283
272 284
285/**
286 * See GNUNET_TESTING_service_run.
287 * The only difference is that we handle the GNUNET_TESTING_Peer to
288 * the RestartableTestMain, so that the peer can be destroyed and re-created
289 * to simulate failure in tests.
290 */
291int
292GNUNET_TESTING_service_run_restartable (const char *testdir,
293 const char *service_name,
294 const char *cfgfilename,
295 GNUNET_TESTING_RestartableTestMain tm,
296 void *tm_cls);
297
298
273 299
274/** 300/**
275 * Sometimes we use the binary name to determine which specific 301 * Sometimes we use the binary name to determine which specific
diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am
index c8e477449..7ddc8e857 100644
--- a/src/testing/Makefile.am
+++ b/src/testing/Makefile.am
@@ -26,6 +26,17 @@ libgnunettesting_la_LDFLAGS = \
26 $(GN_LIB_LDFLAGS) \ 26 $(GN_LIB_LDFLAGS) \
27 -version-info 0:1:0 27 -version-info 0:1:0
28 28
29bin_PROGRAMS = \
30 gnunet-testing-run-service
31
32
33gnunet_testing_run_service_SOURCES = \
34 gnunet-testing-run-service.c
35
36gnunet_testing_run_service_LDADD = \
37 $(top_builddir)/src/util/libgnunetutil.la \
38 $(top_builddir)/src/testing/libgnunettesting.la \
39 $(GN_LIBINTL)
29 40
30check_PROGRAMS = \ 41check_PROGRAMS = \
31 test_testing_portreservation \ 42 test_testing_portreservation \
@@ -59,4 +70,4 @@ test_testing_servicestartup_LDADD = \
59 70
60 71
61EXTRA_DIST = \ 72EXTRA_DIST = \
62 test_testing_defaults.conf \ No newline at end of file 73 test_testing_defaults.conf
diff --git a/src/testing/gnunet-testing-run-service.c b/src/testing/gnunet-testing-run-service.c
new file mode 100644
index 000000000..514c0f420
--- /dev/null
+++ b/src/testing/gnunet-testing-run-service.c
@@ -0,0 +1,187 @@
1/*
2 This file is part of GNUnet.
3 (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors)
4
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.
9
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.
14
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.
19*/
20
21
22/**
23 * @file testing/gnunet-testing-run-service.c
24 * @brief tool to start a service for testing
25 * @author Florian Dold
26 *
27 * Start a peer with the service specified on the command line.
28 * Outputs the path to the temporary configuration file to stdout.
29 *
30 * The peer will run until this program is killed,
31 * or stdin is closed.
32 *
33 * This executable is intended to be used by gnunet-java, in order to reliably
34 * start and stop services for test cases.
35 */
36
37#include "platform.h"
38#include "gnunet_getopt_lib.h"
39#include "gnunet_program_lib.h"
40#include "gnunet_util_lib.h"
41#include "gnunet_signal_lib.h"
42#include "gnunet_testing_lib-new.h"
43#include "gnunet_os_lib.h"
44
45
46static struct GNUNET_DISK_FileHandle fh;
47static char *tmpfilename = NULL;
48static GNUNET_SCHEDULER_TaskIdentifier tid = GNUNET_SCHEDULER_NO_TASK;
49static struct GNUNET_TESTING_Peer *my_peer = NULL;
50
51
52#define LOG(kind,...) \
53 GNUNET_log_from (kind, "gnunettestingnew", __VA_ARGS__)
54
55
56/**
57 * Cleanup called by signal handlers and when stdin is closed.
58 * Removes the temporary file with the configuration and shuts down the scheduler.
59 */
60void
61cleanup (void)
62{
63 if (NULL != tmpfilename)
64 {
65 remove (tmpfilename);
66 }
67 GNUNET_SCHEDULER_shutdown ();
68}
69
70/**
71 * Called whenever we can read stdin non-blocking
72 */
73void
74stdin_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
75{
76 int c;
77
78 if (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)
79 {
80 return;
81 }
82 if (GNUNET_SCHEDULER_REASON_READ_READY & tc->reason)
83 {
84 c = getchar ();
85 if (EOF == c)
86 {
87 tid = GNUNET_SCHEDULER_NO_TASK;
88 cleanup ();
89 }
90 else
91 {
92 if (c == 'r')
93 {
94 GNUNET_TESTING_peer_stop(my_peer);
95 GNUNET_TESTING_peer_start(my_peer);
96 printf("restarted\n");
97 }
98 tid = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, &fh, &stdin_cb, NULL);
99 }
100 return;
101 }
102 GNUNET_break (0);
103}
104
105/**
106 * Main function called by the testing library.
107 * Executed inside a running scheduler.
108 */
109void
110testing_main (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
111 const struct GNUNET_TESTING_Peer *peer)
112{
113 my_peer = peer;
114 tmpfilename = tmpnam (NULL);
115 if (NULL == tmpfilename)
116 {
117 GNUNET_break (0);
118 cleanup ();
119 return;
120 }
121
122 if (GNUNET_SYSERR ==
123 GNUNET_CONFIGURATION_write((struct GNUNET_CONFIGURATION_Handle *) cfg, tmpfilename))
124 {
125 GNUNET_break (0);
126 return;
127 }
128
129 printf("%s\n", tmpfilename);
130 fflush(stdout);
131
132 GNUNET_break(NULL != GNUNET_SIGNAL_handler_install(SIGTERM, &cleanup));
133 GNUNET_break(NULL != GNUNET_SIGNAL_handler_install(SIGINT, &cleanup));
134
135 fh.fd = 0; /* 0=stdin */
136 tid = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, &fh, &stdin_cb, NULL);
137}
138
139
140
141/**
142 * The main function.
143 *
144 * @param argc number of arguments from the command line
145 * @param argv command line arguments
146 * @return 0 ok, 1 on error
147 */
148int
149main (int argc, char *const *argv)
150{
151 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
152 GNUNET_GETOPT_OPTION_HELP("tool to start a service for testing"),
153 GNUNET_GETOPT_OPTION_END
154 };
155 int arg_start;
156 int ret;
157
158 struct GNUNET_OS_Process *p;
159
160 p = GNUNET_OS_start_process(GNUNET_YES, NULL, NULL, "sgjldsjg");
161
162 if (p != NULL) {
163 printf("bogus!\n");
164 }
165
166
167 return 0;
168
169 arg_start = GNUNET_GETOPT_run("gnunet-testing-run-service", options, argc, argv);
170
171 if (arg_start == GNUNET_SYSERR) {
172 return 1;
173 }
174
175 if (arg_start != 1 || argc != 2)
176 {
177 fprintf (stderr, "Invalid number of arguments\n");
178 return 1;
179 }
180
181 ret = GNUNET_TESTING_service_run_restartable ("gnunet_service_test", argv[1],
182 NULL, &testing_main, NULL);
183
184 printf ("bye\n");
185
186 return ret;
187}
diff --git a/src/testing/testing.c b/src/testing/testing.c
index 9e18628c1..fca969b19 100644
--- a/src/testing/testing.c
+++ b/src/testing/testing.c
@@ -922,6 +922,33 @@ struct ServiceContext
922 922
923 923
924/** 924/**
925 * Structure for holding service data
926 */
927struct RestartableServiceContext
928{
929 /**
930 * The configuration of the peer in which the service is run
931 */
932 const struct GNUNET_CONFIGURATION_Handle *cfg;
933
934 /**
935 * Callback to signal service startup
936 */
937 GNUNET_TESTING_RestartableTestMain tm;
938
939 /**
940 * The peer in which the service is run.
941 */
942 const struct GNUNET_TESTING_Peer *peer;
943
944 /**
945 * Closure for the above callback
946 */
947 void *tm_cls;
948};
949
950
951/**
925 * Callback to be called when SCHEDULER has been started 952 * Callback to be called when SCHEDULER has been started
926 * 953 *
927 * @param cls the ServiceContext 954 * @param cls the ServiceContext
@@ -938,6 +965,22 @@ service_run_main (void *cls,
938 965
939 966
940/** 967/**
968 * Callback to be called when SCHEDULER has been started
969 *
970 * @param cls the ServiceContext
971 * @param tc the TaskContext
972 */
973static void
974service_run_restartable_main (void *cls,
975 const struct GNUNET_SCHEDULER_TaskContext *tc)
976{
977 struct RestartableServiceContext *sc = cls;
978
979 sc->tm (sc->tm_cls, sc->cfg, sc->peer);
980}
981
982
983/**
941 * Start a single service (no ARM, except of course if the given 984 * Start a single service (no ARM, except of course if the given
942 * service name is 'arm') and run a test using the testing library. 985 * service name is 'arm') and run a test using the testing library.
943 * Starts a service using the given configuration and then invokes the 986 * Starts a service using the given configuration and then invokes the
@@ -1020,6 +1063,76 @@ GNUNET_TESTING_service_run (const char *testdir,
1020} 1063}
1021 1064
1022 1065
1066
1067/**
1068 * See GNUNET_TESTING_service_run.
1069 * The only difference is that we handle the GNUNET_TESTING_Peer to
1070 * the RestartableTestMain, so that the peer can be destroyed and re-created
1071 * to simulate failure in tests.
1072 */
1073int
1074GNUNET_TESTING_service_run_restartable (const char *testdir,
1075 const char *service_name,
1076 const char *cfgfilename,
1077 GNUNET_TESTING_RestartableTestMain tm,
1078 void *tm_cls)
1079{
1080 struct RestartableServiceContext sc;
1081 struct GNUNET_TESTING_System *system;
1082 struct GNUNET_TESTING_Peer *peer;
1083 struct GNUNET_CONFIGURATION_Handle *cfg;
1084
1085 GNUNET_log_setup (testdir,
1086 "WARNING",
1087 NULL);
1088 system = GNUNET_TESTING_system_create (testdir, "127.0.0.1");
1089 if (NULL == system)
1090 return 1;
1091 cfg = GNUNET_CONFIGURATION_create ();
1092 if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfgfilename))
1093 {
1094 LOG (GNUNET_ERROR_TYPE_ERROR,
1095 _("Failed to load configuration from %s\n"), cfgfilename);
1096 GNUNET_CONFIGURATION_destroy (cfg);
1097 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1098 return 1;
1099 }
1100 peer = GNUNET_TESTING_peer_configure (system, cfg, 0, NULL, NULL);
1101 if (NULL == peer)
1102 {
1103 GNUNET_CONFIGURATION_destroy (cfg);
1104 hostkeys_unload (system);
1105 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1106 return 1;
1107 }
1108 GNUNET_free (peer->main_binary);
1109 GNUNET_asprintf (&peer->main_binary, "gnunet-service-%s", service_name);
1110 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer))
1111 {
1112 GNUNET_TESTING_peer_destroy (peer);
1113 GNUNET_CONFIGURATION_destroy (cfg);
1114 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1115 return 1;
1116 }
1117 sc.cfg = cfg;
1118 sc.tm = tm;
1119 sc.tm_cls = tm_cls;
1120 sc.peer = peer;
1121 GNUNET_SCHEDULER_run (&service_run_restartable_main, &sc); /* Scheduler loop */
1122 if (GNUNET_OK != GNUNET_TESTING_peer_stop (peer))
1123 {
1124 GNUNET_TESTING_peer_destroy (peer);
1125 GNUNET_CONFIGURATION_destroy (cfg);
1126 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1127 return 1;
1128 }
1129 GNUNET_TESTING_peer_destroy (peer);
1130 GNUNET_CONFIGURATION_destroy (cfg);
1131 GNUNET_TESTING_system_destroy (system, GNUNET_YES);
1132 return 0;
1133}
1134
1135
1023/** 1136/**
1024 * Sometimes we use the binary name to determine which specific 1137 * Sometimes we use the binary name to determine which specific
1025 * test to run. In those cases, the string after the last "_" 1138 * test to run. In those cases, the string after the last "_"