test_common_logging_runtime_loglevels.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2011 GNUnet e.V.
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @file util/test_common_logging_runtime_loglevels.c
  18. * @brief testcase for the logging module (runtime log level adjustment)
  19. * @author LRN
  20. */
  21. #include "platform.h"
  22. #include "gnunet_util_lib.h"
  23. #define VERBOSE GNUNET_NO
  24. /**
  25. * How much time the child is allowed to waste on skipped log calls, at most.
  26. * Raspberry Pi takes 113 microseconds tops, this is 3x that value.
  27. */
  28. #define MAX_SKIP_DELAY GNUNET_TIME_relative_multiply ( \
  29. GNUNET_TIME_UNIT_MICROSECONDS, 400).rel_value_us
  30. /**
  31. * How much time non-skipped log call should take, at least.
  32. * Keep in sync with the value in the dummy!
  33. */
  34. #define OUTPUT_DELAY GNUNET_TIME_relative_multiply ( \
  35. GNUNET_TIME_UNIT_MICROSECONDS, 1000).rel_value_us
  36. static int ok;
  37. static int phase = 0;
  38. static struct GNUNET_OS_Process *proc;
  39. /* Pipe to read from started processes stdout (on read end) */
  40. static struct GNUNET_DISK_PipeHandle *pipe_stdout;
  41. static struct GNUNET_SCHEDULER_Task *die_task;
  42. static struct GNUNET_SCHEDULER_Task *read_task;
  43. static void
  44. runone (void);
  45. static void
  46. end_task (void *cls)
  47. {
  48. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending phase %d, ok is %d\n", phase,
  49. ok);
  50. if (NULL != proc)
  51. {
  52. if (0 != GNUNET_OS_process_kill (proc, GNUNET_TERM_SIG))
  53. {
  54. GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
  55. }
  56. GNUNET_OS_process_wait (proc);
  57. GNUNET_OS_process_destroy (proc);
  58. proc = NULL;
  59. }
  60. if (NULL != read_task)
  61. {
  62. GNUNET_SCHEDULER_cancel (read_task);
  63. read_task = NULL;
  64. }
  65. GNUNET_DISK_pipe_close (pipe_stdout);
  66. if (ok == 1)
  67. {
  68. if (phase < 9)
  69. {
  70. phase += 1;
  71. runone ();
  72. }
  73. else
  74. ok = 0;
  75. }
  76. else
  77. GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "failing\n");
  78. }
  79. static char *
  80. read_output_line (int phase_from1, int phase_to1, int phase_from2,
  81. int phase_to2, char c, const char *expect_level,
  82. long delay_morethan, long delay_lessthan, int phase,
  83. char *p,
  84. int *len, long *delay, char level[8])
  85. {
  86. char *r = p;
  87. char t[7];
  88. int i, j, stop = 0;
  89. int level_matches;
  90. int delay_is_sane;
  91. int delay_is_a_dummy;
  92. int delay_outside_of_range;
  93. j = 0;
  94. int stage = 0;
  95. if (! ((phase >= phase_from1) && (phase <= phase_to1)) &&
  96. ! ((phase >= phase_from2) && (phase <= phase_to2)))
  97. return p;
  98. #if 0
  99. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  100. "Trying to match '%c%s \\d\\r\\n' on %s\n", c, expect_level, p);
  101. #endif
  102. for (i = 0; i < *len && ! stop; i++)
  103. {
  104. switch (stage)
  105. {
  106. case 0: /* read first char */
  107. if (r[i] != c)
  108. {
  109. GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Expected '%c', but got '%c'\n", c,
  110. r[i]);
  111. GNUNET_break (0);
  112. return NULL;
  113. }
  114. stage += 1;
  115. break;
  116. case 1: /* read at most 7 char-long error level string, finished by ' ' */
  117. if (r[i] == ' ')
  118. {
  119. level[j] = '\0';
  120. stage += 1;
  121. j = 0;
  122. }
  123. else if (i == 8)
  124. {
  125. GNUNET_break (0);
  126. ok = 2;
  127. return NULL;
  128. }
  129. else
  130. level[j++] = r[i];
  131. break;
  132. case 2: /* read the delay, finished by '\n' */
  133. t[j++] = r[i];
  134. if (r[i] == '\n')
  135. {
  136. t[j - 1] = '\0';
  137. *delay = strtol (t, NULL, 10);
  138. stop = 1;
  139. }
  140. break;
  141. }
  142. }
  143. level_matches = (strcmp (expect_level, level) == 0);
  144. delay_is_sane = (*delay >= 0) && (*delay <= 1000000);
  145. delay_is_a_dummy = (c == 'L');
  146. /* Delay must be either less than 'lessthan' (log call is skipped)
  147. * or more than 'morethan' (log call is not skipped)
  148. */
  149. delay_outside_of_range = ((*delay < delay_lessthan) || (*delay >=
  150. delay_morethan));
  151. if (delay_is_a_dummy)
  152. delay_outside_of_range = 1;
  153. if (! stop)
  154. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  155. "Wrong log format?\n");
  156. if (! level_matches)
  157. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  158. "Wrong log level\n");
  159. if (! delay_is_sane)
  160. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  161. "Delay %ld is insane\n",
  162. *delay);
  163. if (! delay_outside_of_range)
  164. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  165. "Delay %ld is not outside of range (%ld ; %ld)\n",
  166. *delay,
  167. delay_lessthan,
  168. delay_morethan);
  169. if (! stop || ! level_matches || ! delay_is_sane || ! delay_outside_of_range)
  170. return NULL;
  171. *len = *len - i;
  172. return &r[i];
  173. }
  174. /**
  175. * Up to 8 non-skipped GNUNET_log() calls
  176. * + extra line with delay for each one
  177. */
  178. #define LOG_MAX_NUM_LINES (8 * 2)
  179. /**
  180. * Actual message is 17 chars at most
  181. */
  182. #define LOG_MAX_LINE_LENGTH (17)
  183. #define LOG_BUFFER_SIZE LOG_MAX_NUM_LINES *LOG_MAX_LINE_LENGTH
  184. static char buf[LOG_BUFFER_SIZE];
  185. static char *buf_ptr;
  186. static int bytes;
  187. static void
  188. read_call (void *cls)
  189. {
  190. const struct GNUNET_DISK_FileHandle *stdout_read_handle = cls;
  191. char level[8];
  192. long delay;
  193. long delays[8];
  194. int rd;
  195. read_task = NULL;
  196. rd = GNUNET_DISK_file_read (stdout_read_handle, buf_ptr,
  197. sizeof(buf) - bytes);
  198. if (rd > 0)
  199. {
  200. buf_ptr += rd;
  201. bytes += rd;
  202. #if VERBOSE
  203. fprintf (stderr, "got %d bytes, reading more\n", rd);
  204. #endif
  205. read_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
  206. stdout_read_handle,
  207. &read_call,
  208. (void *) stdout_read_handle);
  209. return;
  210. }
  211. #if VERBOSE
  212. fprintf (stderr, "bytes is %d:%s\n", bytes, buf);
  213. #endif
  214. /* +------CHILD OUTPUT--
  215. * | SOFT HARD
  216. * | E W I D E W I D
  217. * | 0E * * *
  218. * | 1W * * * *
  219. * P 2I * * * * *
  220. * H 3D * * * * * *
  221. * A
  222. * S 4E * *
  223. * E 5W * * * *
  224. * | 6I * * * * * *
  225. * | 7D * * * * * * * *
  226. * | 8 * * * *
  227. * | 9 * * * *
  228. */char *p = buf;
  229. if ((bytes == LOG_BUFFER_SIZE) ||
  230. ! (p =
  231. read_output_line (0, 3, 4, 9, 'L', "ERROR", -1,
  232. 1, phase, p,
  233. &bytes, &delay, level)) ||
  234. ! (p =
  235. read_output_line (0, 3, 4, 9, '1', "ERROR", OUTPUT_DELAY,
  236. MAX_SKIP_DELAY, phase, p,
  237. &bytes, &delays[0], level)) ||
  238. ! (p =
  239. read_output_line (1, 3, 5, 9, 'L', "WARNING", -1,
  240. 1, phase, p,
  241. &bytes, &delay, level)) ||
  242. ! (p =
  243. read_output_line (0, 3, 4, 9, '1', "WARNING", OUTPUT_DELAY,
  244. MAX_SKIP_DELAY, phase, p,
  245. &bytes, &delays[1], level)) ||
  246. ! (p =
  247. read_output_line (2, 3, 6, 7, 'L', "INFO", -1,
  248. 1, phase, p,
  249. &bytes, &delay, level)) ||
  250. ! (p =
  251. read_output_line (0, 3, 4, 9, '1', "INFO", OUTPUT_DELAY,
  252. MAX_SKIP_DELAY, phase, p,
  253. &bytes, &delays[2], level)) ||
  254. ! (p =
  255. read_output_line (3, 3, 7, 7, 'L', "DEBUG", -1,
  256. 1, phase, p,
  257. &bytes, &delay, level)) ||
  258. ! (p =
  259. read_output_line (0, 3, 4, 9, '1', "DEBUG", OUTPUT_DELAY,
  260. MAX_SKIP_DELAY, phase, p,
  261. &bytes, &delays[3], level)) ||
  262. ! (p =
  263. read_output_line (0, 3, 4, 9, 'L', "ERROR", -1,
  264. 1, phase, p,
  265. &bytes, &delay, level)) ||
  266. ! (p =
  267. read_output_line (0, 3, 4, 9, '2', "ERROR", OUTPUT_DELAY,
  268. MAX_SKIP_DELAY, phase, p,
  269. &bytes, &delays[4], level)) ||
  270. ! (p =
  271. read_output_line (0, 3, 5, 9, 'L', "WARNING", -1,
  272. 1, phase, p,
  273. &bytes, &delay, level)) ||
  274. ! (p =
  275. read_output_line (0, 3, 4, 9, '2', "WARNING", OUTPUT_DELAY,
  276. MAX_SKIP_DELAY, phase, p,
  277. &bytes, &delays[5], level)) ||
  278. ! (p =
  279. read_output_line (-1, -1, 6, 7, 'L', "INFO", -1,
  280. 1, phase, p,
  281. &bytes, &delay, level)) ||
  282. ! (p =
  283. read_output_line (0, 3, 4, 9, '2', "INFO", OUTPUT_DELAY,
  284. MAX_SKIP_DELAY, phase, p,
  285. &bytes, &delays[6], level)) ||
  286. ! (p =
  287. read_output_line (-1, -1, 7, 7, 'L', "DEBUG", -1,
  288. 1, phase, p,
  289. &bytes, &delay, level)) ||
  290. ! (p =
  291. read_output_line (0, 3, 4, 9, '2', "DEBUG", OUTPUT_DELAY,
  292. MAX_SKIP_DELAY, phase, p,
  293. &bytes, &delays[7], level)))
  294. {
  295. if (bytes == LOG_BUFFER_SIZE)
  296. fprintf (stderr, "%s", "Ran out of buffer space!\n");
  297. GNUNET_break (0);
  298. ok = 2;
  299. GNUNET_SCHEDULER_cancel (die_task);
  300. GNUNET_SCHEDULER_add_now (&end_task, NULL);
  301. return;
  302. }
  303. GNUNET_SCHEDULER_cancel (die_task);
  304. GNUNET_SCHEDULER_add_now (&end_task, NULL);
  305. }
  306. static void
  307. runone ()
  308. {
  309. const struct GNUNET_DISK_FileHandle *stdout_read_handle;
  310. pipe_stdout = GNUNET_DISK_pipe (GNUNET_DISK_PF_BLOCKING_RW);
  311. if (pipe_stdout == NULL)
  312. {
  313. GNUNET_break (0);
  314. ok = 2;
  315. return;
  316. }
  317. putenv ("GNUNET_LOG=");
  318. putenv ("GNUNET_FORCE_LOG=");
  319. putenv ("GNUNET_FORCE_LOGFILE=");
  320. switch (phase)
  321. {
  322. case 0:
  323. putenv ("GNUNET_LOG=;;;;ERROR");
  324. break;
  325. case 1:
  326. putenv ("GNUNET_LOG=;;;;WARNING");
  327. break;
  328. case 2:
  329. putenv ("GNUNET_LOG=;;;;INFO");
  330. break;
  331. case 3:
  332. putenv ("GNUNET_LOG=;;;;DEBUG");
  333. break;
  334. case 4:
  335. putenv ("GNUNET_FORCE_LOG=;;;;ERROR");
  336. break;
  337. case 5:
  338. putenv ("GNUNET_FORCE_LOG=;;;;WARNING");
  339. break;
  340. case 6:
  341. putenv ("GNUNET_FORCE_LOG=;;;;INFO");
  342. break;
  343. case 7:
  344. putenv ("GNUNET_FORCE_LOG=;;;;DEBUG");
  345. break;
  346. case 8:
  347. putenv ("GNUNET_LOG=blah;;;;ERROR");
  348. break;
  349. case 9:
  350. putenv ("GNUNET_FORCE_LOG=blah;;;;ERROR");
  351. break;
  352. }
  353. proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
  354. NULL, pipe_stdout, NULL,
  355. "./test_common_logging_dummy",
  356. "test_common_logging_dummy", NULL);
  357. GNUNET_assert (NULL != proc);
  358. putenv ("GNUNET_FORCE_LOG=");
  359. putenv ("GNUNET_LOG=");
  360. /* Close the write end of the read pipe */
  361. GNUNET_DISK_pipe_close_end (pipe_stdout, GNUNET_DISK_PIPE_END_WRITE);
  362. stdout_read_handle =
  363. GNUNET_DISK_pipe_handle (pipe_stdout, GNUNET_DISK_PIPE_END_READ);
  364. die_task =
  365. GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
  366. (GNUNET_TIME_UNIT_SECONDS, 10),
  367. &end_task,
  368. NULL);
  369. bytes = 0;
  370. buf_ptr = buf;
  371. memset (&buf, 0, sizeof(buf));
  372. read_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
  373. stdout_read_handle,
  374. &read_call,
  375. (void *) stdout_read_handle);
  376. }
  377. static void
  378. task (void *cls)
  379. {
  380. phase = 0;
  381. runone ();
  382. }
  383. int
  384. main (int argc, char *argv[])
  385. {
  386. GNUNET_log_setup ("test-common-logging-runtime-loglevels",
  387. "WARNING",
  388. NULL);
  389. ok = 1;
  390. GNUNET_SCHEDULER_run (&task, &ok);
  391. return ok;
  392. }
  393. /* end of test_common_logging_runtime_loglevels.c */