diff options
author | Florian Dold <florian.dold@gmail.com> | 2012-06-12 22:26:07 +0000 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2012-06-12 22:26:07 +0000 |
commit | b441997d46bfa7e722dc2cd939f79890ff6ca8fd (patch) | |
tree | e2a7ed44ba8bd8d3b1570c2feed7d96ff1676048 | |
parent | 1489edfdd05db78cbe2d66be4d274e7f69af48b0 (diff) | |
download | gnunet-b441997d46bfa7e722dc2cd939f79890ff6ca8fd.tar.gz gnunet-b441997d46bfa7e722dc2cd939f79890ff6ca8fd.zip |
added a command line tool for running and controlling services for testing
-rw-r--r-- | src/include/gnunet_testing_lib-new.h | 26 | ||||
-rw-r--r-- | src/testing/Makefile.am | 13 | ||||
-rw-r--r-- | src/testing/gnunet-testing-run-service.c | 187 | ||||
-rw-r--r-- | src/testing/testing.c | 113 |
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 | */ | ||
228 | typedef 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 | */ | ||
291 | int | ||
292 | GNUNET_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 | ||
29 | bin_PROGRAMS = \ | ||
30 | gnunet-testing-run-service | ||
31 | |||
32 | |||
33 | gnunet_testing_run_service_SOURCES = \ | ||
34 | gnunet-testing-run-service.c | ||
35 | |||
36 | gnunet_testing_run_service_LDADD = \ | ||
37 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
38 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
39 | $(GN_LIBINTL) | ||
29 | 40 | ||
30 | check_PROGRAMS = \ | 41 | check_PROGRAMS = \ |
31 | test_testing_portreservation \ | 42 | test_testing_portreservation \ |
@@ -59,4 +70,4 @@ test_testing_servicestartup_LDADD = \ | |||
59 | 70 | ||
60 | 71 | ||
61 | EXTRA_DIST = \ | 72 | EXTRA_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 | |||
46 | static struct GNUNET_DISK_FileHandle fh; | ||
47 | static char *tmpfilename = NULL; | ||
48 | static GNUNET_SCHEDULER_TaskIdentifier tid = GNUNET_SCHEDULER_NO_TASK; | ||
49 | static 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 | */ | ||
60 | void | ||
61 | cleanup (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 | */ | ||
73 | void | ||
74 | stdin_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 | */ | ||
109 | void | ||
110 | testing_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 | */ | ||
148 | int | ||
149 | main (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 | */ | ||
927 | struct 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 | */ | ||
973 | static void | ||
974 | service_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 | */ | ||
1073 | int | ||
1074 | GNUNET_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 "_" |