glitch in the license text detected by hyazinthe, thank you!
[oweals/gnunet.git] / src / util / test_os_start_process.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14 */
15 /**
16  * @file util/test_os_start_process.c
17  * @brief testcase for os start process code
18  *
19  * This testcase simply calls the os start process code
20  * giving a file descriptor to write stdout to.  If the
21  * correct data "HELLO" is read then all is well.
22  */
23 #include "platform.h"
24 #include "gnunet_util_lib.h"
25 #include "disk.h"
26
27
28 static const char *test_phrase = "HELLO WORLD";
29
30 static int ok;
31
32 static struct GNUNET_OS_Process *proc;
33
34 /**
35  * Pipe to write to started processes stdin (on write end)
36  */
37 static struct GNUNET_DISK_PipeHandle *hello_pipe_stdin;
38
39 /**
40  * Pipe to read from started processes stdout (on read end)
41  */
42 static struct GNUNET_DISK_PipeHandle *hello_pipe_stdout;
43
44 static struct GNUNET_SCHEDULER_Task * die_task;
45
46 struct read_context
47 {
48   char buf[16];
49   int buf_offset;
50   const struct GNUNET_DISK_FileHandle *stdout_read_handle;
51 };
52
53
54 static struct read_context rc;
55
56
57 static void
58 end_task (void *cls)
59 {
60   if (0 != GNUNET_OS_process_kill (proc, GNUNET_TERM_SIG))
61   {
62     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
63   }
64   GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (proc));
65   GNUNET_OS_process_destroy (proc);
66   proc = NULL;
67   GNUNET_DISK_pipe_close (hello_pipe_stdout);
68   GNUNET_DISK_pipe_close (hello_pipe_stdin);
69 }
70
71
72 static void
73 read_call (void *cls)
74 {
75   int bytes;
76
77   bytes = GNUNET_DISK_file_read (rc.stdout_read_handle,
78                                  &rc.buf[rc.buf_offset],
79                                  sizeof (rc.buf) - rc.buf_offset);
80   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
81               "bytes is %d\n",
82               bytes);
83
84   if (bytes < 1)
85   {
86     GNUNET_break (0);
87     ok = 1;
88     GNUNET_SCHEDULER_cancel (die_task);
89     (void) GNUNET_SCHEDULER_add_now (&end_task, NULL);
90     return;
91   }
92
93   ok = strncmp (rc.buf, test_phrase, strlen (test_phrase));
94   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
95               "read %s\n",
96               &rc.buf[rc.buf_offset]);
97   rc.buf_offset += bytes;
98
99   if (0 == ok)
100   {
101     GNUNET_SCHEDULER_cancel (die_task);
102     (void) GNUNET_SCHEDULER_add_now (&end_task, NULL);
103     return;
104   }
105
106   GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
107                                   rc.stdout_read_handle,
108                                   &read_call,
109                                   NULL);
110 }
111
112
113 static void
114 run_task (void *cls)
115 {
116   char *fn;
117   const struct GNUNET_DISK_FileHandle *stdout_read_handle;
118   const struct GNUNET_DISK_FileHandle *wh;
119
120 #if !WINDOWS
121   GNUNET_asprintf (&fn, "cat");
122 #else
123   GNUNET_asprintf (&fn, "w32cat");
124 #endif
125
126   hello_pipe_stdin = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO);
127   hello_pipe_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES);
128
129   if ((hello_pipe_stdout == NULL) || (hello_pipe_stdin == NULL))
130   {
131     GNUNET_break (0);
132     ok = 1;
133     GNUNET_free (fn);
134     return;
135   }
136
137   proc =
138       GNUNET_OS_start_process (GNUNET_NO, GNUNET_OS_INHERIT_STD_ERR,
139                                hello_pipe_stdin, hello_pipe_stdout, NULL,
140                                fn,
141                                "test_gnunet_echo_hello", "-", NULL);
142   GNUNET_free (fn);
143
144   /* Close the write end of the read pipe */
145   GNUNET_DISK_pipe_close_end (hello_pipe_stdout, GNUNET_DISK_PIPE_END_WRITE);
146   /* Close the read end of the write pipe */
147   GNUNET_DISK_pipe_close_end (hello_pipe_stdin, GNUNET_DISK_PIPE_END_READ);
148
149   wh = GNUNET_DISK_pipe_handle (hello_pipe_stdin, GNUNET_DISK_PIPE_END_WRITE);
150
151   /* Write the test_phrase to the cat process */
152   if (GNUNET_DISK_file_write (wh, test_phrase, strlen (test_phrase) + 1) !=
153       strlen (test_phrase) + 1)
154   {
155     GNUNET_break (0);
156     ok = 1;
157     return;
158   }
159
160   /* Close the write end to end the cycle! */
161   GNUNET_DISK_pipe_close_end (hello_pipe_stdin, GNUNET_DISK_PIPE_END_WRITE);
162
163   stdout_read_handle =
164       GNUNET_DISK_pipe_handle (hello_pipe_stdout, GNUNET_DISK_PIPE_END_READ);
165
166   die_task =
167       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
168                                     (GNUNET_TIME_UNIT_MINUTES, 1),
169                                     &end_task,
170                                     NULL);
171
172   memset (&rc, 0, sizeof (rc));
173   rc.stdout_read_handle = stdout_read_handle;
174   GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
175                                   stdout_read_handle,
176                                   &read_call,
177                                   NULL);
178 }
179
180
181 /**
182  * Main method, starts scheduler with task1,
183  * checks that "ok" is correct at the end.
184  */
185 static int
186 check_run ()
187 {
188   ok = 1;
189   GNUNET_SCHEDULER_run (&run_task, &ok);
190   return ok;
191 }
192
193
194 /**
195  * Test killing via pipe.
196  */
197 static int
198 check_kill ()
199 {
200   char *fn;
201
202   hello_pipe_stdin = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO);
203   hello_pipe_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES);
204   if ((hello_pipe_stdout == NULL) || (hello_pipe_stdin == NULL))
205   {
206     return 1;
207   }
208   fn = GNUNET_OS_get_libexec_binary_path ("gnunet-service-resolver");
209   proc =
210     GNUNET_OS_start_process (GNUNET_YES, GNUNET_OS_INHERIT_STD_ERR,
211                              hello_pipe_stdin,
212                              hello_pipe_stdout,
213                              NULL,
214                              fn,
215                              "gnunet-service-resolver", "-",
216                              NULL);
217   sleep (1); /* give process time to start, so we actually use the pipe-kill mechanism! */
218   GNUNET_free (fn);
219   if (0 != GNUNET_OS_process_kill (proc, GNUNET_TERM_SIG))
220     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
221   GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (proc));
222   GNUNET_OS_process_destroy (proc);
223   proc = NULL;
224   GNUNET_DISK_pipe_close (hello_pipe_stdout);
225   GNUNET_DISK_pipe_close (hello_pipe_stdin);
226   return 0;
227 }
228
229
230 /**
231  * Test killing via pipe.
232  */
233 static int
234 check_instant_kill ()
235 {
236   char *fn;
237
238   hello_pipe_stdin = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO);
239   hello_pipe_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES);
240   if ((hello_pipe_stdout == NULL) || (hello_pipe_stdin == NULL))
241   {
242     return 1;
243   }
244   fn = GNUNET_OS_get_libexec_binary_path ("gnunet-service-resolver");
245   proc =
246     GNUNET_OS_start_process (GNUNET_YES, GNUNET_OS_INHERIT_STD_ERR,
247                              hello_pipe_stdin, hello_pipe_stdout, NULL,
248                              fn,
249                              "gnunet-service-resolver", "-", NULL);
250   if (0 != GNUNET_OS_process_kill (proc, GNUNET_TERM_SIG))
251   {
252     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
253   }
254   GNUNET_free (fn);
255   GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (proc));
256   GNUNET_OS_process_destroy (proc);
257   proc = NULL;
258   GNUNET_DISK_pipe_close (hello_pipe_stdout);
259   GNUNET_DISK_pipe_close (hello_pipe_stdin);
260   return 0;
261 }
262
263
264 int
265 main (int argc, char *argv[])
266 {
267   int ret;
268
269   GNUNET_log_setup ("test-os-start-process",
270                     "WARNING",
271                     NULL);
272   ret = 0;
273   ret |= check_run ();
274   ret |= check_kill ();
275   ret |= check_instant_kill ();
276   return ret;
277 }
278
279 /* end of test_os_start_process.c */