123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453 |
- /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "runner.h"
- #include "task.h"
- #include "uv.h"
- char executable_path[sizeof(executable_path)];
- static int compare_task(const void* va, const void* vb) {
- const task_entry_t* a = va;
- const task_entry_t* b = vb;
- return strcmp(a->task_name, b->task_name);
- }
- const char* fmt(double d) {
- static char buf[1024];
- static char* p;
- uint64_t v;
- if (p == NULL)
- p = buf;
- p += 31;
- if (p >= buf + sizeof(buf))
- return "<buffer too small>";
- v = (uint64_t) d;
- #if 0 /* works but we don't care about fractional precision */
- if (d - v >= 0.01) {
- *--p = '0' + (uint64_t) (d * 100) % 10;
- *--p = '0' + (uint64_t) (d * 10) % 10;
- *--p = '.';
- }
- #endif
- if (v == 0)
- *--p = '0';
- while (v) {
- if (v) *--p = '0' + (v % 10), v /= 10;
- if (v) *--p = '0' + (v % 10), v /= 10;
- if (v) *--p = '0' + (v % 10), v /= 10;
- if (v) *--p = ',';
- }
- return p;
- }
- int run_tests(int benchmark_output) {
- int actual;
- int total;
- int passed;
- int failed;
- int skipped;
- int current;
- int test_result;
- int skip;
- task_entry_t* task;
- /* Count the number of tests. */
- actual = 0;
- total = 0;
- for (task = TASKS; task->main; task++, actual++) {
- if (!task->is_helper) {
- total++;
- }
- }
- /* Keep platform_output first. */
- skip = (actual > 0 && 0 == strcmp(TASKS[0].task_name, "platform_output"));
- qsort(TASKS + skip, actual - skip, sizeof(TASKS[0]), compare_task);
- fprintf(stderr, "1..%d\n", total);
- fflush(stderr);
- /* Run all tests. */
- passed = 0;
- failed = 0;
- skipped = 0;
- current = 1;
- for (task = TASKS; task->main; task++) {
- if (task->is_helper) {
- continue;
- }
- test_result = run_test(task->task_name, benchmark_output, current);
- switch (test_result) {
- case TEST_OK: passed++; break;
- case TEST_SKIP: skipped++; break;
- default: failed++;
- }
- current++;
- }
- return failed;
- }
- void log_tap_result(int test_count,
- const char* test,
- int status,
- process_info_t* process) {
- const char* result;
- const char* directive;
- char reason[1024];
- int reason_length;
- switch (status) {
- case TEST_OK:
- result = "ok";
- directive = "";
- break;
- case TEST_SKIP:
- result = "ok";
- directive = " # SKIP ";
- break;
- default:
- result = "not ok";
- directive = "";
- }
- if (status == TEST_SKIP && process_output_size(process) > 0) {
- process_read_last_line(process, reason, sizeof reason);
- reason_length = strlen(reason);
- if (reason_length > 0 && reason[reason_length - 1] == '\n')
- reason[reason_length - 1] = '\0';
- } else {
- reason[0] = '\0';
- }
- fprintf(stderr, "%s %d - %s%s%s\n", result, test_count, test, directive, reason);
- fflush(stderr);
- }
- int run_test(const char* test,
- int benchmark_output,
- int test_count) {
- char errmsg[1024] = "";
- process_info_t processes[1024];
- process_info_t *main_proc;
- task_entry_t* task;
- int timeout_multiplier;
- int process_count;
- int result;
- int status;
- int i;
- status = 255;
- main_proc = NULL;
- process_count = 0;
- #ifndef _WIN32
- /* Clean up stale socket from previous run. */
- remove(TEST_PIPENAME);
- remove(TEST_PIPENAME_2);
- remove(TEST_PIPENAME_3);
- #endif
- /* If it's a helper the user asks for, start it directly. */
- for (task = TASKS; task->main; task++) {
- if (task->is_helper && strcmp(test, task->process_name) == 0) {
- return task->main();
- }
- }
- /* Start the helpers first. */
- for (task = TASKS; task->main; task++) {
- if (strcmp(test, task->task_name) != 0) {
- continue;
- }
- /* Skip the test itself. */
- if (!task->is_helper) {
- continue;
- }
- if (process_start(task->task_name,
- task->process_name,
- &processes[process_count],
- 1 /* is_helper */) == -1) {
- snprintf(errmsg,
- sizeof errmsg,
- "Process `%s` failed to start.",
- task->process_name);
- goto out;
- }
- process_count++;
- }
- /* Now start the test itself. */
- for (task = TASKS; task->main; task++) {
- if (strcmp(test, task->task_name) != 0) {
- continue;
- }
- if (task->is_helper) {
- continue;
- }
- if (process_start(task->task_name,
- task->process_name,
- &processes[process_count],
- 0 /* !is_helper */) == -1) {
- snprintf(errmsg,
- sizeof errmsg,
- "Process `%s` failed to start.",
- task->process_name);
- goto out;
- }
- main_proc = &processes[process_count];
- process_count++;
- break;
- }
- if (main_proc == NULL) {
- snprintf(errmsg,
- sizeof errmsg,
- "No test with that name: %s",
- test);
- goto out;
- }
- timeout_multiplier = 1;
- #ifndef _WIN32
- do {
- const char* var;
- var = getenv("UV_TEST_TIMEOUT_MULTIPLIER");
- if (var == NULL)
- break;
- timeout_multiplier = atoi(var);
- if (timeout_multiplier <= 0)
- timeout_multiplier = 1;
- } while (0);
- #endif
- result = process_wait(main_proc, 1, task->timeout * timeout_multiplier);
- if (result == -1) {
- FATAL("process_wait failed");
- } else if (result == -2) {
- /* Don't have to clean up the process, process_wait() has killed it. */
- snprintf(errmsg,
- sizeof errmsg,
- "timeout");
- goto out;
- }
- status = process_reap(main_proc);
- if (status != TEST_OK) {
- snprintf(errmsg,
- sizeof errmsg,
- "exit code %d",
- status);
- goto out;
- }
- if (benchmark_output) {
- /* Give the helpers time to clean up their act. */
- uv_sleep(1000);
- }
- out:
- /* Reap running processes except the main process, it's already dead. */
- for (i = 0; i < process_count - 1; i++) {
- process_terminate(&processes[i]);
- }
- if (process_count > 0 &&
- process_wait(processes, process_count - 1, -1) < 0) {
- FATAL("process_wait failed");
- }
- log_tap_result(test_count, test, status, &processes[i]);
- /* Show error and output from processes if the test failed. */
- if ((status != TEST_OK && status != TEST_SKIP) || task->show_output) {
- if (strlen(errmsg) > 0)
- fprintf(stderr, "# %s\n", errmsg);
- fprintf(stderr, "# ");
- fflush(stderr);
- for (i = 0; i < process_count; i++) {
- switch (process_output_size(&processes[i])) {
- case -1:
- fprintf(stderr, "Output from process `%s`: (unavailable)\n",
- process_get_name(&processes[i]));
- fflush(stderr);
- break;
- case 0:
- fprintf(stderr, "Output from process `%s`: (no output)\n",
- process_get_name(&processes[i]));
- fflush(stderr);
- break;
- default:
- fprintf(stderr, "Output from process `%s`:\n", process_get_name(&processes[i]));
- fflush(stderr);
- process_copy_output(&processes[i], stderr);
- break;
- }
- }
- /* In benchmark mode show concise output from the main process. */
- } else if (benchmark_output) {
- switch (process_output_size(main_proc)) {
- case -1:
- fprintf(stderr, "%s: (unavailable)\n", test);
- fflush(stderr);
- break;
- case 0:
- fprintf(stderr, "%s: (no output)\n", test);
- fflush(stderr);
- break;
- default:
- for (i = 0; i < process_count; i++) {
- process_copy_output(&processes[i], stderr);
- }
- break;
- }
- }
- /* Clean up all process handles. */
- for (i = 0; i < process_count; i++) {
- process_cleanup(&processes[i]);
- }
- return status;
- }
- /* Returns the status code of the task part
- * or 255 if no matching task was not found.
- */
- int run_test_part(const char* test, const char* part) {
- task_entry_t* task;
- int r;
- for (task = TASKS; task->main; task++) {
- if (strcmp(test, task->task_name) == 0 &&
- strcmp(part, task->process_name) == 0) {
- r = task->main();
- return r;
- }
- }
- fprintf(stderr, "No test part with that name: %s:%s\n", test, part);
- fflush(stderr);
- return 255;
- }
- static int find_helpers(const task_entry_t* task,
- const task_entry_t** helpers) {
- const task_entry_t* helper;
- int n_helpers;
- for (n_helpers = 0, helper = TASKS; helper->main; helper++) {
- if (helper->is_helper && strcmp(helper->task_name, task->task_name) == 0) {
- *helpers++ = helper;
- n_helpers++;
- }
- }
- return n_helpers;
- }
- void print_tests(FILE* stream) {
- const task_entry_t* helpers[1024];
- const task_entry_t* task;
- int n_helpers;
- int n_tasks;
- int i;
- for (n_tasks = 0, task = TASKS; task->main; n_tasks++, task++);
- qsort(TASKS, n_tasks, sizeof(TASKS[0]), compare_task);
- for (task = TASKS; task->main; task++) {
- if (task->is_helper) {
- continue;
- }
- n_helpers = find_helpers(task, helpers);
- if (n_helpers) {
- printf("%-25s (helpers:", task->task_name);
- for (i = 0; i < n_helpers; i++) {
- printf(" %s", helpers[i]->process_name);
- }
- printf(")\n");
- } else {
- printf("%s\n", task->task_name);
- }
- }
- }
- void print_lines(const char* buffer, size_t size, FILE* stream) {
- const char* start;
- const char* end;
- start = buffer;
- while ((end = memchr(start, '\n', &buffer[size] - start))) {
- fputs("# ", stream);
- fwrite(start, 1, (int)(end - start), stream);
- fputs("\n", stream);
- fflush(stream);
- start = end + 1;
- }
- end = &buffer[size];
- if (start < end) {
- fputs("# ", stream);
- fwrite(start, 1, (int)(end - start), stream);
- fputs("\n", stream);
- fflush(stream);
- }
- }
|