• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
30 char executable_path[sizeof(executable_path)];
31 
32 
compare_task(const void * va,const void * vb)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 
fmt(double d)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 
run_tests(int benchmark_output)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(stdout, "1..%d\n", total);
102   fflush(stdout);
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 
log_tap_result(int test_count,const char * test,int status,process_info_t * process)127 void log_tap_result(int test_count,
128                     const char* test,
129                     int status,
130                     process_info_t* process) {
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(stdout, "%s %d - %s%s%s\n", result, test_count, test, directive, reason);
160   fflush(stdout);
161 }
162 
163 
run_test(const char * test,int benchmark_output,int test_count)164 int run_test(const char* test,
165              int benchmark_output,
166              int test_count) {
167   char errmsg[1024] = "";
168   process_info_t processes[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++) {
297     process_terminate(&processes[i]);
298   }
299 
300   if (process_count > 0 &&
301       process_wait(processes, process_count - 1, -1) < 0) {
302     FATAL("process_wait failed");
303   }
304 
305   log_tap_result(test_count, test, status, &processes[i]);
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(stdout, "# %s\n", errmsg);
311     fprintf(stdout, "# ");
312     fflush(stdout);
313 
314     for (i = 0; i < process_count; i++) {
315       switch (process_output_size(&processes[i])) {
316        case -1:
317         fprintf(stdout, "Output from process `%s`: (unavailable)\n",
318                 process_get_name(&processes[i]));
319         fflush(stdout);
320         break;
321 
322        case 0:
323         fprintf(stdout, "Output from process `%s`: (no output)\n",
324                 process_get_name(&processes[i]));
325         fflush(stdout);
326         break;
327 
328        default:
329         fprintf(stdout, "Output from process `%s`:\n", process_get_name(&processes[i]));
330         fflush(stdout);
331         process_copy_output(&processes[i], stdout);
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(stdout, "%s: (unavailable)\n", test);
341       fflush(stdout);
342       break;
343 
344      case 0:
345       fprintf(stdout, "%s: (no output)\n", test);
346       fflush(stdout);
347       break;
348 
349      default:
350       for (i = 0; i < process_count; i++) {
351         process_copy_output(&processes[i], stdout);
352       }
353       break;
354     }
355   }
356 
357   /* Clean up all process handles. */
358   for (i = 0; i < process_count; i++) {
359     process_cleanup(&processes[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  */
run_test_part(const char * test,const char * part)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(stdout, "No test part with that name: %s:%s\n", test, part);
382   fflush(stdout);
383   return 255;
384 }
385 
386 
387 
find_helpers(const task_entry_t * task,const task_entry_t ** helpers)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 
print_tests(FILE * stream)404 void print_tests(FILE* stream) {
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 
print_lines(const char * buffer,size_t size,FILE * stream)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 }
454