tst-support_capture_subprocess.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. /* Test capturing output from a subprocess.
  2. Copyright (C) 2017-2019 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, see
  14. <http://www.gnu.org/licenses/>. */
  15. #include <stdbool.h>
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <support/capture_subprocess.h>
  20. #include <support/check.h>
  21. #include <support/support.h>
  22. #include <sys/wait.h>
  23. #include <unistd.h>
  24. /* Write one byte at *P to FD and advance *P. Do nothing if *P is
  25. '\0'. */
  26. static void
  27. transfer (const unsigned char **p, int fd)
  28. {
  29. if (**p != '\0')
  30. {
  31. TEST_VERIFY (write (fd, *p, 1) == 1);
  32. ++*p;
  33. }
  34. }
  35. /* Determine the order in which stdout and stderr are written. */
  36. enum write_mode { out_first, err_first, interleave,
  37. write_mode_last = interleave };
  38. /* Describe what to write in the subprocess. */
  39. struct test
  40. {
  41. char *out;
  42. char *err;
  43. enum write_mode write_mode;
  44. int signal;
  45. int status;
  46. };
  47. /* For use with support_capture_subprocess. */
  48. static void
  49. callback (void *closure)
  50. {
  51. const struct test *test = closure;
  52. bool mode_ok = false;
  53. switch (test->write_mode)
  54. {
  55. case out_first:
  56. TEST_VERIFY (fputs (test->out, stdout) >= 0);
  57. TEST_VERIFY (fflush (stdout) == 0);
  58. TEST_VERIFY (fputs (test->err, stderr) >= 0);
  59. TEST_VERIFY (fflush (stderr) == 0);
  60. mode_ok = true;
  61. break;
  62. case err_first:
  63. TEST_VERIFY (fputs (test->err, stderr) >= 0);
  64. TEST_VERIFY (fflush (stderr) == 0);
  65. TEST_VERIFY (fputs (test->out, stdout) >= 0);
  66. TEST_VERIFY (fflush (stdout) == 0);
  67. mode_ok = true;
  68. break;
  69. case interleave:
  70. {
  71. const unsigned char *pout = (const unsigned char *) test->out;
  72. const unsigned char *perr = (const unsigned char *) test->err;
  73. do
  74. {
  75. transfer (&pout, STDOUT_FILENO);
  76. transfer (&perr, STDERR_FILENO);
  77. }
  78. while (*pout != '\0' || *perr != '\0');
  79. }
  80. mode_ok = true;
  81. break;
  82. }
  83. TEST_VERIFY (mode_ok);
  84. if (test->signal != 0)
  85. raise (test->signal);
  86. exit (test->status);
  87. }
  88. /* Create a heap-allocated random string of letters. */
  89. static char *
  90. random_string (size_t length)
  91. {
  92. char *result = xmalloc (length + 1);
  93. for (size_t i = 0; i < length; ++i)
  94. result[i] = 'a' + (rand () % 26);
  95. result[length] = '\0';
  96. return result;
  97. }
  98. /* Check that the specific stream from the captured subprocess matches
  99. expectations. */
  100. static void
  101. check_stream (const char *what, const struct xmemstream *stream,
  102. const char *expected)
  103. {
  104. if (strcmp (stream->buffer, expected) != 0)
  105. {
  106. support_record_failure ();
  107. printf ("error: captured %s data incorrect\n"
  108. " expected: %s\n"
  109. " actual: %s\n",
  110. what, expected, stream->buffer);
  111. }
  112. if (stream->length != strlen (expected))
  113. {
  114. support_record_failure ();
  115. printf ("error: captured %s data length incorrect\n"
  116. " expected: %zu\n"
  117. " actual: %zu\n",
  118. what, strlen (expected), stream->length);
  119. }
  120. }
  121. static int
  122. do_test (void)
  123. {
  124. const int lengths[] = {0, 1, 17, 512, 20000, -1};
  125. /* Test multiple combinations of support_capture_subprocess.
  126. length_idx_stdout: Index into the lengths array above,
  127. controls how many bytes are written by the subprocess to
  128. standard output.
  129. length_idx_stderr: Same for standard error.
  130. write_mode: How standard output and standard error writes are
  131. ordered.
  132. signal: Exit with no signal if zero, with SIGTERM if one.
  133. status: Process exit status: 0 if zero, 3 if one. */
  134. for (int length_idx_stdout = 0; lengths[length_idx_stdout] >= 0;
  135. ++length_idx_stdout)
  136. for (int length_idx_stderr = 0; lengths[length_idx_stderr] >= 0;
  137. ++length_idx_stderr)
  138. for (int write_mode = 0; write_mode < write_mode_last; ++write_mode)
  139. for (int signal = 0; signal < 2; ++signal)
  140. for (int status = 0; status < 2; ++status)
  141. {
  142. struct test test =
  143. {
  144. .out = random_string (lengths[length_idx_stdout]),
  145. .err = random_string (lengths[length_idx_stderr]),
  146. .write_mode = write_mode,
  147. .signal = signal * SIGTERM, /* 0 or SIGTERM. */
  148. .status = status * 3, /* 0 or 3. */
  149. };
  150. TEST_VERIFY (strlen (test.out) == lengths[length_idx_stdout]);
  151. TEST_VERIFY (strlen (test.err) == lengths[length_idx_stderr]);
  152. struct support_capture_subprocess result
  153. = support_capture_subprocess (callback, &test);
  154. check_stream ("stdout", &result.out, test.out);
  155. check_stream ("stderr", &result.err, test.err);
  156. /* Allowed output for support_capture_subprocess_check. */
  157. int check_allow = 0;
  158. if (lengths[length_idx_stdout] > 0)
  159. check_allow |= sc_allow_stdout;
  160. if (lengths[length_idx_stderr] > 0)
  161. check_allow |= sc_allow_stderr;
  162. if (check_allow == 0)
  163. check_allow = sc_allow_none;
  164. if (test.signal != 0)
  165. {
  166. TEST_VERIFY (WIFSIGNALED (result.status));
  167. TEST_VERIFY (WTERMSIG (result.status) == test.signal);
  168. support_capture_subprocess_check (&result, "signal",
  169. -SIGTERM, check_allow);
  170. }
  171. else
  172. {
  173. TEST_VERIFY (WIFEXITED (result.status));
  174. TEST_VERIFY (WEXITSTATUS (result.status) == test.status);
  175. support_capture_subprocess_check (&result, "exit",
  176. test.status, check_allow);
  177. }
  178. support_capture_subprocess_free (&result);
  179. free (test.out);
  180. free (test.err);
  181. }
  182. return 0;
  183. }
  184. #include <support/test-driver.c>