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