libuv-svace-build
435 строк · 10.3 Кб
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
30char executable_path[sizeof(executable_path)];31
32
33static int compare_task(const void* va, const void* vb) {34const task_entry_t* a = va;35const task_entry_t* b = vb;36return strcmp(a->task_name, b->task_name);37}
38
39
40char* fmt(char (*buf)[32], double d) {41uint64_t v;42char* p;43
44p = &(*buf)[32];45v = (uint64_t) d;46
47*--p = '\0';48
49if (v == 0)50*--p = '0';51
52while (v) {53if (v) *--p = '0' + (v % 10), v /= 10;54if (v) *--p = '0' + (v % 10), v /= 10;55if (v) *--p = '0' + (v % 10), v /= 10;56if (v) *--p = ',';57}58
59return p;60}
61
62
63int run_tests(int benchmark_output) {64int actual;65int total;66int failed;67int current;68int test_result;69int skip;70task_entry_t* task;71
72/* Count the number of tests. */73actual = 0;74total = 0;75for (task = TASKS; task->main; task++, actual++) {76if (!task->is_helper) {77total++;78}79}80
81/* Keep platform_output first. */82skip = (actual > 0 && 0 == strcmp(TASKS[0].task_name, "platform_output"));83qsort(TASKS + skip, actual - skip, sizeof(TASKS[0]), compare_task);84
85fprintf(stdout, "1..%d\n", total);86fflush(stdout);87
88/* Run all tests. */89failed = 0;90current = 1;91for (task = TASKS; task->main; task++) {92if (task->is_helper) {93continue;94}95
96test_result = run_test(task->task_name, benchmark_output, current);97switch (test_result) {98case TEST_OK: break;99case TEST_SKIP: break;100default: failed++;101}102current++;103}104
105return failed;106}
107
108
109void log_tap_result(int test_count,110const char* test,111int status,112process_info_t* process) {113const char* result;114const char* directive;115char reason[1024];116int reason_length;117
118switch (status) {119case TEST_OK:120result = "ok";121directive = "";122break;123case TEST_SKIP:124result = "ok";125directive = " # SKIP ";126break;127default:128result = "not ok";129directive = "";130}131
132if (status == TEST_SKIP && process_output_size(process) > 0) {133process_read_last_line(process, reason, sizeof reason);134reason_length = strlen(reason);135if (reason_length > 0 && reason[reason_length - 1] == '\n')136reason[reason_length - 1] = '\0';137} else {138reason[0] = '\0';139}140
141fprintf(stdout, "%s %d - %s%s%s\n", result, test_count, test, directive, reason);142fflush(stdout);143}
144
145
146int run_test(const char* test,147int benchmark_output,148int test_count) {149char errmsg[1024] = "";150process_info_t processes[1024];151process_info_t *main_proc;152task_entry_t* task;153int timeout_multiplier;154int process_count;155int result;156int status;157int i;158
159status = 255;160main_proc = NULL;161process_count = 0;162
163#ifndef _WIN32164/* Clean up stale socket from previous run. */165remove(TEST_PIPENAME);166remove(TEST_PIPENAME_2);167remove(TEST_PIPENAME_3);168#endif169
170/* If it's a helper the user asks for, start it directly. */171for (task = TASKS; task->main; task++) {172if (task->is_helper && strcmp(test, task->process_name) == 0) {173return task->main();174}175}176
177/* Start the helpers first. */178for (task = TASKS; task->main; task++) {179if (strcmp(test, task->task_name) != 0) {180continue;181}182
183/* Skip the test itself. */184if (!task->is_helper) {185continue;186}187
188if (process_start(task->task_name,189task->process_name,190&processes[process_count],1911 /* is_helper */) == -1) {192snprintf(errmsg,193sizeof errmsg,194"Process `%s` failed to start.",195task->process_name);196goto out;197}198
199process_count++;200}201
202/* Now start the test itself. */203for (task = TASKS; task->main; task++) {204if (strcmp(test, task->task_name) != 0) {205continue;206}207
208if (task->is_helper) {209continue;210}211
212if (process_start(task->task_name,213task->process_name,214&processes[process_count],2150 /* !is_helper */) == -1) {216snprintf(errmsg,217sizeof errmsg,218"Process `%s` failed to start.",219task->process_name);220goto out;221}222
223main_proc = &processes[process_count];224process_count++;225break;226}227
228if (main_proc == NULL) {229snprintf(errmsg,230sizeof errmsg,231"No test with that name: %s",232test);233goto out;234}235
236timeout_multiplier = 1;237#ifndef _WIN32238do {239const char* var;240
241var = getenv("UV_TEST_TIMEOUT_MULTIPLIER");242if (var == NULL)243break;244
245timeout_multiplier = atoi(var);246if (timeout_multiplier <= 0)247timeout_multiplier = 1;248} while (0);249#endif250
251result = process_wait(main_proc, 1, task->timeout * timeout_multiplier);252if (result == -1) {253FATAL("process_wait failed");254} else if (result == -2) {255/* Don't have to clean up the process, process_wait() has killed it. */256snprintf(errmsg,257sizeof errmsg,258"timeout");259goto out;260}261
262status = process_reap(main_proc);263if (status != TEST_OK) {264snprintf(errmsg,265sizeof errmsg,266"exit code %d",267status);268goto out;269}270
271if (benchmark_output) {272/* Give the helpers time to clean up their act. */273uv_sleep(1000);274}275
276out:277/* Reap running processes except the main process, it's already dead. */278for (i = 0; i < process_count - 1; i++) {279process_terminate(&processes[i]);280}281
282if (process_count > 0 &&283process_wait(processes, process_count - 1, -1) < 0) {284FATAL("process_wait failed");285}286
287log_tap_result(test_count, test, status, &processes[i]);288
289/* Show error and output from processes if the test failed. */290if ((status != TEST_OK && status != TEST_SKIP) || task->show_output) {291if (strlen(errmsg) > 0)292fprintf(stdout, "# %s\n", errmsg);293fprintf(stdout, "# ");294fflush(stdout);295
296for (i = 0; i < process_count; i++) {297switch (process_output_size(&processes[i])) {298case -1:299fprintf(stdout, "Output from process `%s`: (unavailable)\n",300process_get_name(&processes[i]));301fflush(stdout);302break;303
304case 0:305fprintf(stdout, "Output from process `%s`: (no output)\n",306process_get_name(&processes[i]));307fflush(stdout);308break;309
310default:311fprintf(stdout, "Output from process `%s`:\n", process_get_name(&processes[i]));312fflush(stdout);313process_copy_output(&processes[i], stdout);314break;315}316}317
318/* In benchmark mode show concise output from the main process. */319} else if (benchmark_output) {320switch (process_output_size(main_proc)) {321case -1:322fprintf(stdout, "%s: (unavailable)\n", test);323fflush(stdout);324break;325
326case 0:327fprintf(stdout, "%s: (no output)\n", test);328fflush(stdout);329break;330
331default:332for (i = 0; i < process_count; i++) {333process_copy_output(&processes[i], stdout);334}335break;336}337}338
339/* Clean up all process handles. */340for (i = 0; i < process_count; i++) {341process_cleanup(&processes[i]);342}343
344return status;345}
346
347
348/* Returns the status code of the task part
349* or 255 if no matching task was not found.
350*/
351int run_test_part(const char* test, const char* part) {352task_entry_t* task;353int r;354
355for (task = TASKS; task->main; task++) {356if (strcmp(test, task->task_name) == 0 &&357strcmp(part, task->process_name) == 0) {358r = task->main();359return r;360}361}362
363fprintf(stdout, "No test part with that name: %s:%s\n", test, part);364fflush(stdout);365return 255;366}
367
368
369
370static int find_helpers(const task_entry_t* task,371const task_entry_t** helpers) {372const task_entry_t* helper;373int n_helpers;374
375for (n_helpers = 0, helper = TASKS; helper->main; helper++) {376if (helper->is_helper && strcmp(helper->task_name, task->task_name) == 0) {377*helpers++ = helper;378n_helpers++;379}380}381
382return n_helpers;383}
384
385
386void print_tests(FILE* stream) {387const task_entry_t* helpers[1024];388const task_entry_t* task;389int n_helpers;390int n_tasks;391int i;392
393for (n_tasks = 0, task = TASKS; task->main; n_tasks++, task++);394qsort(TASKS, n_tasks, sizeof(TASKS[0]), compare_task);395
396for (task = TASKS; task->main; task++) {397if (task->is_helper) {398continue;399}400
401n_helpers = find_helpers(task, helpers);402if (n_helpers) {403printf("%-25s (helpers:", task->task_name);404for (i = 0; i < n_helpers; i++) {405printf(" %s", helpers[i]->process_name);406}407printf(")\n");408} else {409printf("%s\n", task->task_name);410}411}412}
413
414
415void print_lines(const char* buffer, size_t size, FILE* stream) {416const char* start;417const char* end;418
419start = buffer;420while ((end = memchr(start, '\n', &buffer[size] - start))) {421fputs("# ", stream);422fwrite(start, 1, (int)(end - start), stream);423fputs("\n", stream);424fflush(stream);425start = end + 1;426}427
428end = &buffer[size];429if (start < end) {430fputs("# ", stream);431fwrite(start, 1, (int)(end - start), stream);432fputs("\n", stream);433fflush(stream);434}435}
436