runner.c
Go to the documentation of this file.
1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a copy
4  * of this software and associated documentation files (the "Software"), to
5  * deal in the Software without restriction, including without limitation the
6  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7  * sell copies of the Software, and to permit persons to whom the Software is
8  * furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19  * IN THE SOFTWARE.
20  */
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 
26 #include "runner.h"
27 #include "task.h"
28 #include "uv.h"
29 
31 
32 
33 static int compare_task(const void* va, const void* vb) {
34  const task_entry_t* a = va;
35  const task_entry_t* b = vb;
36  return strcmp(a->task_name, b->task_name);
37 }
38 
39 
40 const char* fmt(double d) {
41  static char buf[1024];
42  static char* p;
43  uint64_t v;
44 
45  if (p == NULL)
46  p = buf;
47 
48  p += 31;
49 
50  if (p >= buf + sizeof(buf))
51  return "<buffer too small>";
52 
53  v = (uint64_t) d;
54 
55 #if 0 /* works but we don't care about fractional precision */
56  if (d - v >= 0.01) {
57  *--p = '0' + (uint64_t) (d * 100) % 10;
58  *--p = '0' + (uint64_t) (d * 10) % 10;
59  *--p = '.';
60  }
61 #endif
62 
63  if (v == 0)
64  *--p = '0';
65 
66  while (v) {
67  if (v) *--p = '0' + (v % 10), v /= 10;
68  if (v) *--p = '0' + (v % 10), v /= 10;
69  if (v) *--p = '0' + (v % 10), v /= 10;
70  if (v) *--p = ',';
71  }
72 
73  return p;
74 }
75 
76 
77 int run_tests(int benchmark_output) {
78  int actual;
79  int total;
80  int passed;
81  int failed;
82  int skipped;
83  int current;
84  int test_result;
85  int skip;
86  task_entry_t* task;
87 
88  /* Count the number of tests. */
89  actual = 0;
90  total = 0;
91  for (task = TASKS; task->main; task++, actual++) {
92  if (!task->is_helper) {
93  total++;
94  }
95  }
96 
97  /* Keep platform_output first. */
98  skip = (actual > 0 && 0 == strcmp(TASKS[0].task_name, "platform_output"));
99  qsort(TASKS + skip, actual - skip, sizeof(TASKS[0]), compare_task);
100 
101  fprintf(stderr, "1..%d\n", total);
102  fflush(stderr);
103 
104  /* Run all tests. */
105  passed = 0;
106  failed = 0;
107  skipped = 0;
108  current = 1;
109  for (task = TASKS; task->main; task++) {
110  if (task->is_helper) {
111  continue;
112  }
113 
114  test_result = run_test(task->task_name, benchmark_output, current);
115  switch (test_result) {
116  case TEST_OK: passed++; break;
117  case TEST_SKIP: skipped++; break;
118  default: failed++;
119  }
120  current++;
121  }
122 
123  return failed;
124 }
125 
126 
128  const char* test,
129  int status,
131  const char* result;
132  const char* directive;
133  char reason[1024];
134  int reason_length;
135 
136  switch (status) {
137  case TEST_OK:
138  result = "ok";
139  directive = "";
140  break;
141  case TEST_SKIP:
142  result = "ok";
143  directive = " # SKIP ";
144  break;
145  default:
146  result = "not ok";
147  directive = "";
148  }
149 
150  if (status == TEST_SKIP && process_output_size(process) > 0) {
151  process_read_last_line(process, reason, sizeof reason);
152  reason_length = strlen(reason);
153  if (reason_length > 0 && reason[reason_length - 1] == '\n')
154  reason[reason_length - 1] = '\0';
155  } else {
156  reason[0] = '\0';
157  }
158 
159  fprintf(stderr, "%s %d - %s%s%s\n", result, test_count, test, directive, reason);
160  fflush(stderr);
161 }
162 
163 
164 int run_test(const char* test,
165  int benchmark_output,
166  int test_count) {
167  char errmsg[1024] = "";
169  process_info_t *main_proc;
170  task_entry_t* task;
171  int timeout_multiplier;
172  int process_count;
173  int result;
174  int status;
175  int i;
176 
177  status = 255;
178  main_proc = NULL;
179  process_count = 0;
180 
181 #ifndef _WIN32
182  /* Clean up stale socket from previous run. */
183  remove(TEST_PIPENAME);
184  remove(TEST_PIPENAME_2);
185  remove(TEST_PIPENAME_3);
186 #endif
187 
188  /* If it's a helper the user asks for, start it directly. */
189  for (task = TASKS; task->main; task++) {
190  if (task->is_helper && strcmp(test, task->process_name) == 0) {
191  return task->main();
192  }
193  }
194 
195  /* Start the helpers first. */
196  for (task = TASKS; task->main; task++) {
197  if (strcmp(test, task->task_name) != 0) {
198  continue;
199  }
200 
201  /* Skip the test itself. */
202  if (!task->is_helper) {
203  continue;
204  }
205 
206  if (process_start(task->task_name,
207  task->process_name,
208  &processes[process_count],
209  1 /* is_helper */) == -1) {
210  snprintf(errmsg,
211  sizeof errmsg,
212  "Process `%s` failed to start.",
213  task->process_name);
214  goto out;
215  }
216 
217  process_count++;
218  }
219 
220  /* Now start the test itself. */
221  for (task = TASKS; task->main; task++) {
222  if (strcmp(test, task->task_name) != 0) {
223  continue;
224  }
225 
226  if (task->is_helper) {
227  continue;
228  }
229 
230  if (process_start(task->task_name,
231  task->process_name,
232  &processes[process_count],
233  0 /* !is_helper */) == -1) {
234  snprintf(errmsg,
235  sizeof errmsg,
236  "Process `%s` failed to start.",
237  task->process_name);
238  goto out;
239  }
240 
241  main_proc = &processes[process_count];
242  process_count++;
243  break;
244  }
245 
246  if (main_proc == NULL) {
247  snprintf(errmsg,
248  sizeof errmsg,
249  "No test with that name: %s",
250  test);
251  goto out;
252  }
253 
254  timeout_multiplier = 1;
255 #ifndef _WIN32
256  do {
257  const char* var;
258 
259  var = getenv("UV_TEST_TIMEOUT_MULTIPLIER");
260  if (var == NULL)
261  break;
262 
263  timeout_multiplier = atoi(var);
264  if (timeout_multiplier <= 0)
265  timeout_multiplier = 1;
266  } while (0);
267 #endif
268 
269  result = process_wait(main_proc, 1, task->timeout * timeout_multiplier);
270  if (result == -1) {
271  FATAL("process_wait failed");
272  } else if (result == -2) {
273  /* Don't have to clean up the process, process_wait() has killed it. */
274  snprintf(errmsg,
275  sizeof errmsg,
276  "timeout");
277  goto out;
278  }
279 
280  status = process_reap(main_proc);
281  if (status != TEST_OK) {
282  snprintf(errmsg,
283  sizeof errmsg,
284  "exit code %d",
285  status);
286  goto out;
287  }
288 
289  if (benchmark_output) {
290  /* Give the helpers time to clean up their act. */
291  uv_sleep(1000);
292  }
293 
294 out:
295  /* Reap running processes except the main process, it's already dead. */
296  for (i = 0; i < process_count - 1; i++) {
298  }
299 
300  if (process_count > 0 &&
301  process_wait(processes, process_count - 1, -1) < 0) {
302  FATAL("process_wait failed");
303  }
304 
306 
307  /* Show error and output from processes if the test failed. */
308  if ((status != TEST_OK && status != TEST_SKIP) || task->show_output) {
309  if (strlen(errmsg) > 0)
310  fprintf(stderr, "# %s\n", errmsg);
311  fprintf(stderr, "# ");
312  fflush(stderr);
313 
314  for (i = 0; i < process_count; i++) {
315  switch (process_output_size(&processes[i])) {
316  case -1:
317  fprintf(stderr, "Output from process `%s`: (unavailable)\n",
319  fflush(stderr);
320  break;
321 
322  case 0:
323  fprintf(stderr, "Output from process `%s`: (no output)\n",
325  fflush(stderr);
326  break;
327 
328  default:
329  fprintf(stderr, "Output from process `%s`:\n", process_get_name(&processes[i]));
330  fflush(stderr);
332  break;
333  }
334  }
335 
336  /* In benchmark mode show concise output from the main process. */
337  } else if (benchmark_output) {
338  switch (process_output_size(main_proc)) {
339  case -1:
340  fprintf(stderr, "%s: (unavailable)\n", test);
341  fflush(stderr);
342  break;
343 
344  case 0:
345  fprintf(stderr, "%s: (no output)\n", test);
346  fflush(stderr);
347  break;
348 
349  default:
350  for (i = 0; i < process_count; i++) {
352  }
353  break;
354  }
355  }
356 
357  /* Clean up all process handles. */
358  for (i = 0; i < process_count; i++) {
360  }
361 
362  return status;
363 }
364 
365 
366 /* Returns the status code of the task part
367  * or 255 if no matching task was not found.
368  */
369 int run_test_part(const char* test, const char* part) {
370  task_entry_t* task;
371  int r;
372 
373  for (task = TASKS; task->main; task++) {
374  if (strcmp(test, task->task_name) == 0 &&
375  strcmp(part, task->process_name) == 0) {
376  r = task->main();
377  return r;
378  }
379  }
380 
381  fprintf(stderr, "No test part with that name: %s:%s\n", test, part);
382  fflush(stderr);
383  return 255;
384 }
385 
386 
387 
388 static int find_helpers(const task_entry_t* task,
389  const task_entry_t** helpers) {
390  const task_entry_t* helper;
391  int n_helpers;
392 
393  for (n_helpers = 0, helper = TASKS; helper->main; helper++) {
394  if (helper->is_helper && strcmp(helper->task_name, task->task_name) == 0) {
395  *helpers++ = helper;
396  n_helpers++;
397  }
398  }
399 
400  return n_helpers;
401 }
402 
403 
405  const task_entry_t* helpers[1024];
406  const task_entry_t* task;
407  int n_helpers;
408  int n_tasks;
409  int i;
410 
411  for (n_tasks = 0, task = TASKS; task->main; n_tasks++, task++);
412  qsort(TASKS, n_tasks, sizeof(TASKS[0]), compare_task);
413 
414  for (task = TASKS; task->main; task++) {
415  if (task->is_helper) {
416  continue;
417  }
418 
419  n_helpers = find_helpers(task, helpers);
420  if (n_helpers) {
421  printf("%-25s (helpers:", task->task_name);
422  for (i = 0; i < n_helpers; i++) {
423  printf(" %s", helpers[i]->process_name);
424  }
425  printf(")\n");
426  } else {
427  printf("%s\n", task->task_name);
428  }
429  }
430 }
431 
432 
433 void print_lines(const char* buffer, size_t size, FILE* stream) {
434  const char* start;
435  const char* end;
436 
437  start = buffer;
438  while ((end = memchr(start, '\n', &buffer[size] - start))) {
439  fputs("# ", stream);
440  fwrite(start, 1, (int)(end - start), stream);
441  fputs("\n", stream);
442  fflush(stream);
443  start = end + 1;
444  }
445 
446  end = &buffer[size];
447  if (start < end) {
448  fputs("# ", stream);
449  fwrite(start, 1, (int)(end - start), stream);
450  fputs("\n", stream);
451  fflush(stream);
452  }
453 }
TEST_PIPENAME_2
#define TEST_PIPENAME_2
Definition: task.h:62
_gevent_test_main.result
result
Definition: _gevent_test_main.py:96
process_copy_output
int process_copy_output(process_info_t *p, FILE *stream)
Definition: runner-unix.c:357
gen_build_yaml.out
dictionary out
Definition: src/benchmark/gen_build_yaml.py:24
process_reap
int process_reap(process_info_t *p)
Definition: runner-unix.c:422
task.h
find_helpers
static int find_helpers(const task_entry_t *task, const task_entry_t **helpers)
Definition: runner.c:388
task_entry_t::is_helper
int is_helper
Definition: runner.h:43
mkowners.skip
bool skip
Definition: mkowners.py:224
test
Definition: spinlock_test.cc:36
run_test_part
int run_test_part(const char *test, const char *part)
Definition: runner.c:369
total
size_t total
Definition: cord_analysis.cc:59
string.h
buf
voidpf void * buf
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
printf
_Use_decl_annotations_ int __cdecl printf(const char *_Format,...)
Definition: cs_driver.c:91
run_test
int run_test(const char *test, int benchmark_output, int test_count)
Definition: runner.c:164
executable_path
char executable_path[sizeof(executable_path)]
Definition: runner.c:30
status
absl::Status status
Definition: rls.cc:251
a
int a
Definition: abseil-cpp/absl/container/internal/hash_policy_traits_test.cc:88
xds_manager.p
p
Definition: xds_manager.py:60
grpc::testing::test_result
test_result
Definition: h2_ssl_cert_test.cc:201
compare_task
static int compare_task(const void *va, const void *vb)
Definition: runner.c:33
print_tests
void print_tests(FILE *stream)
Definition: runner.c:404
python_utils.port_server.stderr
stderr
Definition: port_server.py:51
process_cleanup
void process_cleanup(process_info_t *p)
Definition: runner-unix.c:432
task_entry_t::show_output
int show_output
Definition: runner.h:44
run_tests
int run_tests(int benchmark_output)
Definition: runner.c:77
start
static uint64_t start
Definition: benchmark-pound.c:74
process_wait
int process_wait(process_info_t *vec, int n, int timeout)
Definition: runner-unix.c:226
process_start
int process_start(char *name, char *part, process_info_t *p, int is_helper)
Definition: runner-unix.c:81
process
static uv_process_t process
Definition: benchmark-spawn.c:32
end
char * end
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1008
setup.v
v
Definition: third_party/bloaty/third_party/capstone/bindings/python/setup.py:42
task_entry_t
Definition: runner.h:39
task_entry_t::process_name
char * process_name
Definition: runner.h:41
uint64_t
unsigned __int64 uint64_t
Definition: stdint-msvc2008.h:90
test_count
int test_count
Definition: bloaty/third_party/protobuf/conformance/conformance_cpp.cc:69
buffer
char buffer[1024]
Definition: libuv/docs/code/idle-compute/main.c:8
uv_sleep
UV_EXTERN void uv_sleep(unsigned int msec)
Definition: unix/core.c:1521
b
uint64_t b
Definition: abseil-cpp/absl/container/internal/layout_test.cc:53
d
static const fe d
Definition: curve25519_tables.h:19
qsort
void qsort(void *a, size_t n, size_t es, int(*cmp)(const void *, const void *))
Definition: qsort.h:130
task_entry_t::task_name
char * task_name
Definition: runner.h:40
print_lines
void print_lines(const char *buffer, size_t size, FILE *stream)
Definition: runner.c:433
uv.h
runner.h
FATAL
#define FATAL(msg)
Definition: task.h:88
benchmark.FILE
FILE
Definition: benchmark.py:21
task_entry_t::main
int(* main)(void)
Definition: runner.h:42
process_read_last_line
int process_read_last_line(process_info_t *p, char *buffer, size_t buffer_len)
Definition: runner-unix.c:381
TASKS
task_entry_t TASKS[]
fix_build_deps.r
r
Definition: fix_build_deps.py:491
google_benchmark.example.skipped
def skipped(state)
Definition: example.py:54
process_terminate
int process_terminate(process_info_t *p)
Definition: runner-unix.c:416
TEST_OK
@ TEST_OK
Definition: task.h:253
TEST_SKIP
@ TEST_SKIP
Definition: task.h:254
task_entry_t::timeout
int timeout
Definition: runner.h:49
process_output_size
long int process_output_size(process_info_t *p)
Definition: runner-unix.c:343
TEST_PIPENAME
#define TEST_PIPENAME
Definition: task.h:61
process_get_name
char * process_get_name(process_info_t *p)
Definition: runner-unix.c:410
tests.unit._exit_test.processes
list processes
Definition: _exit_test.py:46
patch_major_os_version.vb
vb
Definition: patch_major_os_version.py:24
size
voidpf void uLong size
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
log_tap_result
void log_tap_result(int test_count, const char *test, int status, process_info_t *process)
Definition: runner.c:127
getenv
#define getenv(ptr)
Definition: ares_private.h:106
TEST_PIPENAME_3
#define TEST_PIPENAME_3
Definition: task.h:63
fmt
const char * fmt(double d)
Definition: runner.c:40
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
process_info_t
Definition: runner-unix.h:28
stream
voidpf stream
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136


grpc
Author(s):
autogenerated on Thu Mar 13 2025 03:01:14