-testing LRNs fix from IRC to correct expression logic and move to 200 microsecond...
[oweals/gnunet.git] / src / util / test_common_logging_runtime_loglevels.c
1 /*
2      This file is part of GNUnet.
3      (C) 2011 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  * @file util/test_common_logging_runtime_loglevels.c
23  * @brief testcase for the logging module  (runtime log level adjustment)
24  * @author LRN
25  */
26 #include "platform.h"
27 #include "gnunet_common.h"
28 #include "gnunet_scheduler_lib.h"
29 #include "gnunet_network_lib.h"
30 #include "gnunet_disk_lib.h"
31 #include "gnunet_os_lib.h"
32
33 #define VERBOSE GNUNET_NO
34
35 static int ok;
36
37 static int phase = 0;
38
39 static struct GNUNET_OS_Process *proc;
40
41 /* Pipe to read from started processes stdout (on read end) */
42 static struct GNUNET_DISK_PipeHandle *pipe_stdout;
43
44 static GNUNET_SCHEDULER_TaskIdentifier die_task;
45
46 static GNUNET_SCHEDULER_TaskIdentifier read_task;
47
48 static void
49 runone (void);
50
51
52 static void
53 end_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
54 {
55   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending phase %d, ok is %d\n", phase,
56               ok);
57   if (NULL != proc)
58   {
59     if (0 != GNUNET_OS_process_kill (proc, SIGTERM))
60     {
61       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
62     }
63     GNUNET_OS_process_wait (proc);
64     GNUNET_OS_process_destroy (proc);
65     proc = NULL;
66   }
67   if (GNUNET_SCHEDULER_NO_TASK != read_task)
68   {
69     GNUNET_SCHEDULER_cancel (read_task);
70     read_task = GNUNET_SCHEDULER_NO_TASK;
71   }
72   GNUNET_DISK_pipe_close (pipe_stdout);
73   if (ok == 1)
74   {
75     if (phase < 9)
76     {
77       phase += 1;
78       runone ();
79     }
80     else
81       ok = 0;
82   }
83   else
84     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "failing\n");
85 }
86
87
88 static char *
89 read_output_line (int phase_from1, int phase_to1, int phase_from2,
90                   int phase_to2, char c, const char *expect_level,
91                   long delay_morethan, long delay_lessthan, int phase, 
92                   char *p,
93                   int *len, long *delay, char level[8])
94 {
95   char *r = p;
96   char t[7];
97   int i, j, stop = 0;
98
99   j = 0;
100   int stage = 0;
101
102   if (!(phase >= phase_from1 && phase <= phase_to1) &&
103       !(phase >= phase_from2 && phase <= phase_to2))
104     return p;
105 #if 0
106   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
107               "Trying to match '%c%s \\d\\r\\n' on %s\n", c, expect_level, p);
108 #endif
109   for (i = 0; i < *len && !stop; i++)
110   {
111     switch (stage)
112     {
113     case 0:                    /* read first char */
114       if (r[i] != c)
115       {
116         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Expected '%c', but got '%c'\n", c,
117                     r[i]);
118         GNUNET_break (0);
119         return NULL;
120       }
121       stage += 1;
122       break;
123     case 1:                    /* read at most 7 char-long error level string, finished by ' ' */
124       if (r[i] == ' ')
125       {
126         level[j] = '\0';
127         stage += 1;
128         j = 0;
129       }
130       else if (i == 8)
131       {
132         GNUNET_break (0);
133         ok = 2;
134         return NULL;
135       }
136       else
137         level[j++] = r[i];
138       break;
139     case 2:                    /* read the delay, finished by '\n' */
140       t[j++] = r[i];
141 #if WINDOWS
142       if (r[i] == '\r' && r[i + 1] == '\n')
143       {
144         i += 1;
145         t[j - 1] = '\0';
146         *delay = strtol (t, NULL, 10);
147         stop = 1;
148       }
149 #else
150       if (r[i] == '\n')
151       {
152         t[j - 1] = '\0';
153         *delay = strtol (t, NULL, 10);
154         stop = 1;
155       }
156 #endif
157       break;
158     }
159   }
160   if (!stop || strcmp (expect_level, level) != 0 || *delay < 0 || *delay > 1000
161       || (!((*delay < delay_lessthan) || (*delay > delay_morethan)) && c != '1'
162           && c != '2'))
163     return NULL;
164   *len = *len - i;
165   return &r[i];
166 }
167
168 static char buf[20 * 16];
169
170 static char *buf_ptr;
171
172 static int bytes;
173
174
175 static void
176 read_call (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
177 {
178   const struct GNUNET_DISK_FileHandle *stdout_read_handle = cls;
179   char level[8];
180   long delay;
181   long delays[8];
182   int rd;
183
184   read_task = GNUNET_SCHEDULER_NO_TASK;
185   rd = GNUNET_DISK_file_read (stdout_read_handle, buf_ptr,
186                               sizeof (buf) - bytes);
187   if (rd > 0)
188   {
189     buf_ptr += rd;
190     bytes += rd;
191 #if VERBOSE
192     FPRINTF (stderr, "got %d bytes, reading more\n", rd);
193 #endif
194     read_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
195                                                 stdout_read_handle, &read_call,
196                                                 (void*) stdout_read_handle);
197     return;
198   }
199
200 #if VERBOSE
201   FPRINTF (stderr, "bytes is %d:%s\n", bytes, buf);
202 #endif
203
204   /* +------CHILD OUTPUT--
205    * |      SOFT     HARD
206    * |    E W I D  E W I D
207    * | 0E *        * *
208    * | 1W * *      * *
209    * P 2I * * *    * *
210    * H 3D * * * *  * *
211    * A
212    * S 4E *        *
213    * E 5W * *      * *
214    * | 6I * * *    * * *
215    * | 7D * * * *  * * * *
216    * | 8  * *      * *
217    * | 9  * *      * *
218    */
219   char *p = buf;
220
221   if (bytes == 20 * 16 ||
222       !(p =
223         read_output_line (0, 3, 4, 9, 'L', "ERROR", -1, 1, phase, p, &bytes,
224                           &delay, level)) ||
225       !(p =
226         read_output_line (0, 3, 4, 9, '1', "ERROR", 200, 400, phase, p, &bytes,
227                           &delays[0], level)) ||
228       !(p =
229         read_output_line (1, 3, 5, 9, 'L', "WARNING", -1, 1, phase, p, &bytes,
230                           &delay, level)) ||
231       !(p =
232         read_output_line (0, 3, 4, 9, '1', "WARNING", 200, 400, phase, p,
233                           &bytes, &delays[1], level)) ||
234       !(p =
235         read_output_line (2, 3, 6, 7, 'L', "INFO", -1, 1, phase, p, &bytes,
236                           &delay, level)) ||
237       !(p =
238         read_output_line (0, 3, 4, 9, '1', "INFO", 200, 400, phase, p, &bytes,
239                           &delays[2], level)) ||
240       !(p =
241         read_output_line (3, 3, 7, 7, 'L', "DEBUG", -1, 1, phase, p, &bytes,
242                           &delay, level)) ||
243       !(p =
244         read_output_line (0, 3, 4, 9, '1', "DEBUG", 200, 400, phase, p, &bytes,
245                           &delays[3], level)) ||
246       !(p =
247         read_output_line (0, 3, 4, 9, 'L', "ERROR", -1, 1, phase, p, &bytes,
248                           &delay, level)) ||
249       !(p =
250         read_output_line (0, 3, 4, 9, '2', "ERROR", 200, 400, phase, p, &bytes,
251                           &delays[4], level)) ||
252       !(p =
253         read_output_line (0, 3, 5, 9, 'L', "WARNING", -1, 1, phase, p, &bytes,
254                           &delay, level)) ||
255       !(p =
256         read_output_line (0, 3, 4, 9, '2', "WARNING", 200, 400, phase, p,
257                           &bytes, &delays[5], level)) ||
258       !(p =
259         read_output_line (-1, -1, 6, 7, 'L', "INFO", -1, 1, phase, p, &bytes,
260                           &delay, level)) ||
261       !(p =
262         read_output_line (0, 3, 4, 9, '2', "INFO", 200, 400, phase, p, &bytes,
263                           &delays[6], level)) ||
264       !(p =
265         read_output_line (-1, -1, 7, 7, 'L', "DEBUG", -1, 1, phase, p, &bytes,
266                           &delay, level)) ||
267       !(p =
268         read_output_line (0, 3, 4, 9, '2', "DEBUG", 200, 400, phase, p, &bytes,
269                           &delays[7], level)))
270   {
271     if (bytes == 20 * 16)
272       FPRINTF (stderr, "%s",  "Ran out of buffer space!\n");
273     GNUNET_break (0);
274     ok = 2;
275     GNUNET_SCHEDULER_cancel (die_task);
276     GNUNET_SCHEDULER_add_now (&end_task, NULL);
277     return;
278   }
279
280   GNUNET_SCHEDULER_cancel (die_task);
281   GNUNET_SCHEDULER_add_now (&end_task, NULL);
282 }
283
284
285 static void
286 runone ()
287 {
288   const struct GNUNET_DISK_FileHandle *stdout_read_handle;
289
290   pipe_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES);
291
292   if (pipe_stdout == NULL)
293   {
294     GNUNET_break (0);
295     ok = 2;
296     return;
297   }
298
299   putenv ("GNUNET_LOG=");
300   putenv ("GNUNET_FORCE_LOG=");
301   putenv ("GNUNET_FORCE_LOGFILE=");
302   switch (phase)
303   {
304   case 0:
305     putenv ("GNUNET_LOG=;;;;ERROR");
306     break;
307   case 1:
308     putenv ("GNUNET_LOG=;;;;WARNING");
309     break;
310   case 2:
311     putenv ("GNUNET_LOG=;;;;INFO");
312     break;
313   case 3:
314     putenv ("GNUNET_LOG=;;;;DEBUG");
315     break;
316   case 4:
317     putenv ("GNUNET_FORCE_LOG=;;;;ERROR");
318     break;
319   case 5:
320     putenv ("GNUNET_FORCE_LOG=;;;;WARNING");
321     break;
322   case 6:
323     putenv ("GNUNET_FORCE_LOG=;;;;INFO");
324     break;
325   case 7:
326     putenv ("GNUNET_FORCE_LOG=;;;;DEBUG");
327     break;
328   case 8:
329     putenv ("GNUNET_LOG=blah;;;;ERROR");
330     break;
331   case 9:
332     putenv ("GNUNET_FORCE_LOG=blah;;;;ERROR");
333     break;
334   }
335
336   proc = GNUNET_OS_start_process (GNUNET_NO, GNUNET_OS_INHERIT_STD_OUT_AND_ERR, NULL, pipe_stdout,
337 #if MINGW
338                                   "test_common_logging_dummy",
339 #else
340                                   "./test_common_logging_dummy",
341 #endif
342                                   "test_common_logging_dummy", NULL);
343   GNUNET_assert (NULL != proc);
344   putenv ("GNUNET_FORCE_LOG=");
345   putenv ("GNUNET_LOG=");
346
347   /* Close the write end of the read pipe */
348   GNUNET_DISK_pipe_close_end (pipe_stdout, GNUNET_DISK_PIPE_END_WRITE);
349
350   stdout_read_handle =
351       GNUNET_DISK_pipe_handle (pipe_stdout, GNUNET_DISK_PIPE_END_READ);
352
353   die_task =
354       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
355                                     (GNUNET_TIME_UNIT_SECONDS, 10), &end_task,
356                                     NULL);
357
358   bytes = 0;
359   buf_ptr = buf;
360   memset (&buf, 0, sizeof (buf));
361
362   read_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
363                                               stdout_read_handle, &read_call,
364                                               (void*) stdout_read_handle);
365 }
366
367
368 static void
369 task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
370 {
371   phase = 0;
372   runone ();
373 }
374
375
376 int
377 main (int argc, char *argv[])
378 {
379   GNUNET_log_setup ("test-common-logging-runtime-loglevels",
380                     "WARNING",
381                     NULL);
382   ok = 1;
383   GNUNET_SCHEDULER_run (&task, &ok);
384   return ok;
385 }
386
387 /* end of test_common_logging_runtime_loglevels.c */