runner.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  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. #include <stdio.h>
  22. #include <string.h>
  23. #include "runner.h"
  24. #include "task.h"
  25. #include "uv.h"
  26. char executable_path[PATHMAX] = { '\0' };
  27. int tap_output = 0;
  28. static void log_progress(int total,
  29. int passed,
  30. int failed,
  31. int todos,
  32. int skipped,
  33. const char* name) {
  34. int progress;
  35. if (total == 0)
  36. total = 1;
  37. progress = 100 * (passed + failed + skipped + todos) / total;
  38. LOGF("[%% %3d|+ %3d|- %3d|T %3d|S %3d]: %s",
  39. progress,
  40. passed,
  41. failed,
  42. todos,
  43. skipped,
  44. name);
  45. }
  46. const char* fmt(double d) {
  47. static char buf[1024];
  48. static char* p;
  49. uint64_t v;
  50. if (p == NULL)
  51. p = buf;
  52. p += 31;
  53. if (p >= buf + sizeof(buf))
  54. return "<buffer too small>";
  55. v = (uint64_t) d;
  56. #if 0 /* works but we don't care about fractional precision */
  57. if (d - v >= 0.01) {
  58. *--p = '0' + (uint64_t) (d * 100) % 10;
  59. *--p = '0' + (uint64_t) (d * 10) % 10;
  60. *--p = '.';
  61. }
  62. #endif
  63. if (v == 0)
  64. *--p = '0';
  65. while (v) {
  66. if (v) *--p = '0' + (v % 10), v /= 10;
  67. if (v) *--p = '0' + (v % 10), v /= 10;
  68. if (v) *--p = '0' + (v % 10), v /= 10;
  69. if (v) *--p = ',';
  70. }
  71. return p;
  72. }
  73. int run_tests(int timeout, int benchmark_output) {
  74. int total;
  75. int passed;
  76. int failed;
  77. int todos;
  78. int skipped;
  79. int current;
  80. int test_result;
  81. task_entry_t* task;
  82. /* Count the number of tests. */
  83. total = 0;
  84. for (task = TASKS; task->main; task++) {
  85. if (!task->is_helper) {
  86. total++;
  87. }
  88. }
  89. if (tap_output) {
  90. LOGF("1..%d\n", total);
  91. }
  92. /* Run all tests. */
  93. passed = 0;
  94. failed = 0;
  95. todos = 0;
  96. skipped = 0;
  97. current = 1;
  98. for (task = TASKS; task->main; task++) {
  99. if (task->is_helper) {
  100. continue;
  101. }
  102. if (!tap_output)
  103. rewind_cursor();
  104. if (!benchmark_output && !tap_output) {
  105. log_progress(total, passed, failed, todos, skipped, task->task_name);
  106. }
  107. test_result = run_test(task->task_name, timeout, benchmark_output, current);
  108. switch (test_result) {
  109. case TEST_OK: passed++; break;
  110. case TEST_TODO: todos++; break;
  111. case TEST_SKIP: skipped++; break;
  112. default: failed++;
  113. }
  114. current++;
  115. }
  116. if (!tap_output)
  117. rewind_cursor();
  118. if (!benchmark_output && !tap_output) {
  119. log_progress(total, passed, failed, todos, skipped, "Done.\n");
  120. }
  121. return failed;
  122. }
  123. void log_tap_result(int test_count,
  124. const char* test,
  125. int status,
  126. process_info_t* process) {
  127. const char* result;
  128. const char* directive;
  129. char reason[1024];
  130. switch (status) {
  131. case TEST_OK:
  132. result = "ok";
  133. directive = "";
  134. break;
  135. case TEST_TODO:
  136. result = "not ok";
  137. directive = " # TODO ";
  138. break;
  139. case TEST_SKIP:
  140. result = "ok";
  141. directive = " # SKIP ";
  142. break;
  143. default:
  144. result = "not ok";
  145. directive = "";
  146. }
  147. if ((status == TEST_SKIP || status == TEST_TODO) &&
  148. process_output_size(process) > 0) {
  149. process_read_last_line(process, reason, sizeof reason);
  150. } else {
  151. reason[0] = '\0';
  152. }
  153. LOGF("%s %d - %s%s%s\n", result, test_count, test, directive, reason);
  154. }
  155. int run_test(const char* test,
  156. int timeout,
  157. int benchmark_output,
  158. int test_count) {
  159. char errmsg[1024] = "no error";
  160. process_info_t processes[1024];
  161. process_info_t *main_proc;
  162. task_entry_t* task;
  163. int process_count;
  164. int result;
  165. int status;
  166. int i;
  167. status = 255;
  168. main_proc = NULL;
  169. process_count = 0;
  170. #ifndef _WIN32
  171. /* Clean up stale socket from previous run. */
  172. remove(TEST_PIPENAME);
  173. #endif
  174. /* If it's a helper the user asks for, start it directly. */
  175. for (task = TASKS; task->main; task++) {
  176. if (task->is_helper && strcmp(test, task->process_name) == 0) {
  177. return task->main();
  178. }
  179. }
  180. /* Start the helpers first. */
  181. for (task = TASKS; task->main; task++) {
  182. if (strcmp(test, task->task_name) != 0) {
  183. continue;
  184. }
  185. /* Skip the test itself. */
  186. if (!task->is_helper) {
  187. continue;
  188. }
  189. if (process_start(task->task_name,
  190. task->process_name,
  191. &processes[process_count],
  192. 1 /* is_helper */) == -1) {
  193. snprintf(errmsg,
  194. sizeof errmsg,
  195. "Process `%s` failed to start.",
  196. task->process_name);
  197. goto out;
  198. }
  199. process_count++;
  200. }
  201. /* Give the helpers time to settle. Race-y, fix this. */
  202. uv_sleep(250);
  203. /* Now start the test itself. */
  204. for (task = TASKS; task->main; task++) {
  205. if (strcmp(test, task->task_name) != 0) {
  206. continue;
  207. }
  208. if (task->is_helper) {
  209. continue;
  210. }
  211. if (process_start(task->task_name,
  212. task->process_name,
  213. &processes[process_count],
  214. 0 /* !is_helper */) == -1) {
  215. snprintf(errmsg,
  216. sizeof errmsg,
  217. "Process `%s` failed to start.",
  218. task->process_name);
  219. goto out;
  220. }
  221. main_proc = &processes[process_count];
  222. process_count++;
  223. break;
  224. }
  225. if (main_proc == NULL) {
  226. snprintf(errmsg,
  227. sizeof errmsg,
  228. "No test with that name: %s",
  229. test);
  230. goto out;
  231. }
  232. result = process_wait(main_proc, 1, timeout);
  233. if (result == -1) {
  234. FATAL("process_wait failed");
  235. } else if (result == -2) {
  236. /* Don't have to clean up the process, process_wait() has killed it. */
  237. snprintf(errmsg,
  238. sizeof errmsg,
  239. "timeout");
  240. goto out;
  241. }
  242. status = process_reap(main_proc);
  243. if (status != TEST_OK) {
  244. snprintf(errmsg,
  245. sizeof errmsg,
  246. "exit code %d",
  247. status);
  248. goto out;
  249. }
  250. if (benchmark_output) {
  251. /* Give the helpers time to clean up their act. */
  252. uv_sleep(1000);
  253. }
  254. out:
  255. /* Reap running processes except the main process, it's already dead. */
  256. for (i = 0; i < process_count - 1; i++) {
  257. process_terminate(&processes[i]);
  258. }
  259. if (process_count > 0 &&
  260. process_wait(processes, process_count - 1, -1) < 0) {
  261. FATAL("process_wait failed");
  262. }
  263. if (tap_output)
  264. log_tap_result(test_count, test, status, &processes[i]);
  265. /* Show error and output from processes if the test failed. */
  266. if (status != 0 || task->show_output) {
  267. if (tap_output) {
  268. LOGF("#");
  269. } else if (status == TEST_TODO) {
  270. LOGF("\n`%s` todo\n", test);
  271. } else if (status == TEST_SKIP) {
  272. LOGF("\n`%s` skipped\n", test);
  273. } else if (status != 0) {
  274. LOGF("\n`%s` failed: %s\n", test, errmsg);
  275. } else {
  276. LOGF("\n");
  277. }
  278. for (i = 0; i < process_count; i++) {
  279. switch (process_output_size(&processes[i])) {
  280. case -1:
  281. LOGF("Output from process `%s`: (unavailable)\n",
  282. process_get_name(&processes[i]));
  283. break;
  284. case 0:
  285. LOGF("Output from process `%s`: (no output)\n",
  286. process_get_name(&processes[i]));
  287. break;
  288. default:
  289. LOGF("Output from process `%s`:\n", process_get_name(&processes[i]));
  290. process_copy_output(&processes[i], fileno(stderr));
  291. break;
  292. }
  293. }
  294. if (!tap_output) {
  295. LOG("=============================================================\n");
  296. }
  297. /* In benchmark mode show concise output from the main process. */
  298. } else if (benchmark_output) {
  299. switch (process_output_size(main_proc)) {
  300. case -1:
  301. LOGF("%s: (unavailable)\n", test);
  302. break;
  303. case 0:
  304. LOGF("%s: (no output)\n", test);
  305. break;
  306. default:
  307. for (i = 0; i < process_count; i++) {
  308. process_copy_output(&processes[i], fileno(stderr));
  309. }
  310. break;
  311. }
  312. }
  313. /* Clean up all process handles. */
  314. for (i = 0; i < process_count; i++) {
  315. process_cleanup(&processes[i]);
  316. }
  317. return status;
  318. }
  319. /* Returns the status code of the task part
  320. * or 255 if no matching task was not found.
  321. */
  322. int run_test_part(const char* test, const char* part) {
  323. task_entry_t* task;
  324. int r;
  325. for (task = TASKS; task->main; task++) {
  326. if (strcmp(test, task->task_name) == 0 &&
  327. strcmp(part, task->process_name) == 0) {
  328. r = task->main();
  329. return r;
  330. }
  331. }
  332. LOGF("No test part with that name: %s:%s\n", test, part);
  333. return 255;
  334. }
  335. static int compare_task(const void* va, const void* vb) {
  336. const task_entry_t* a = va;
  337. const task_entry_t* b = vb;
  338. return strcmp(a->task_name, b->task_name);
  339. }
  340. static int find_helpers(const task_entry_t* task, const task_entry_t** helpers) {
  341. const task_entry_t* helper;
  342. int n_helpers;
  343. for (n_helpers = 0, helper = TASKS; helper->main; helper++) {
  344. if (helper->is_helper && strcmp(helper->task_name, task->task_name) == 0) {
  345. *helpers++ = helper;
  346. n_helpers++;
  347. }
  348. }
  349. return n_helpers;
  350. }
  351. void print_tests(FILE* stream) {
  352. const task_entry_t* helpers[1024];
  353. const task_entry_t* task;
  354. int n_helpers;
  355. int n_tasks;
  356. int i;
  357. for (n_tasks = 0, task = TASKS; task->main; n_tasks++, task++);
  358. qsort(TASKS, n_tasks, sizeof(TASKS[0]), compare_task);
  359. for (task = TASKS; task->main; task++) {
  360. if (task->is_helper) {
  361. continue;
  362. }
  363. n_helpers = find_helpers(task, helpers);
  364. if (n_helpers) {
  365. printf("%-25s (helpers:", task->task_name);
  366. for (i = 0; i < n_helpers; i++) {
  367. printf(" %s", helpers[i]->process_name);
  368. }
  369. printf(")\n");
  370. } else {
  371. printf("%s\n", task->task_name);
  372. }
  373. }
  374. }