unittest.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824
  1. /*
  2. * Copyright (C) 2008-2024 Teluu Inc. (http://www.teluu.com)
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. */
  18. #include <pj/unittest.h>
  19. #include <pj/assert.h>
  20. #include <pj/errno.h>
  21. #include <pj/fifobuf.h>
  22. #include <pj/os.h>
  23. #include <pj/rand.h>
  24. #include <pj/string.h>
  25. #define THIS_FILE "unittest.c"
  26. #define INVALID_TLS_ID -1
  27. static long tls_id = INVALID_TLS_ID;
  28. /* When basic runner is used, current test is saved in this global var */
  29. static pj_test_case *tc_main_thread;
  30. /* Forward decls. */
  31. static void unittest_log_callback(int level, const char *data, int len);
  32. static int get_completion_line( const pj_test_case *tc, const char *end_line,
  33. char *log_buf, unsigned buf_size);
  34. /* atexit() callback to free TLS */
  35. static void unittest_shutdown(void)
  36. {
  37. if (tls_id != INVALID_TLS_ID) {
  38. pj_thread_local_free(tls_id);
  39. tls_id = INVALID_TLS_ID;
  40. }
  41. }
  42. /* initialize unittest subsystem. can be called many times. */
  43. static pj_status_t unittest_init(void)
  44. {
  45. #if PJ_HAS_THREADS
  46. if (tls_id == INVALID_TLS_ID) {
  47. pj_status_t status;
  48. status = pj_thread_local_alloc(&tls_id);
  49. if (status != PJ_SUCCESS) {
  50. tls_id = INVALID_TLS_ID;
  51. return status;
  52. }
  53. pj_atexit(&unittest_shutdown);
  54. }
  55. #endif
  56. return PJ_SUCCESS;
  57. }
  58. /* Initialize param with default values */
  59. PJ_DEF(void) pj_test_case_param_default( pj_test_case_param *prm)
  60. {
  61. pj_bzero(prm, sizeof(*prm));
  62. prm->log_level = 6;
  63. }
  64. /* Initialize test case */
  65. PJ_DEF(void) pj_test_case_init( pj_test_case *tc,
  66. const char *obj_name,
  67. unsigned flags,
  68. int (*test_func)(void*),
  69. void *arg,
  70. void *fifobuf_buf,
  71. unsigned buf_size,
  72. const pj_test_case_param *prm)
  73. {
  74. PJ_ASSERT_ON_FAIL( ((flags & (PJ_TEST_KEEP_FIRST|PJ_TEST_KEEP_LAST)) !=
  75. (PJ_TEST_KEEP_FIRST|PJ_TEST_KEEP_LAST)), {} );
  76. pj_bzero(tc, sizeof(*tc));
  77. /* Parameters */
  78. if (prm) {
  79. pj_memcpy(&tc->prm, prm, sizeof(*prm));
  80. } else {
  81. pj_test_case_param_default(&tc->prm);
  82. }
  83. pj_ansi_strxcpy(tc->obj_name, obj_name, sizeof(tc->obj_name));
  84. tc->flags = flags;
  85. tc->test_func = test_func;
  86. tc->arg = arg;
  87. pj_fifobuf_init(&tc->fb, fifobuf_buf, buf_size);
  88. /* Run-time state */
  89. tc->result = PJ_EPENDING;
  90. pj_list_init(&tc->logs);
  91. }
  92. /* Init test suite */
  93. PJ_DEF(void) pj_test_suite_init(pj_test_suite *suite)
  94. {
  95. pj_bzero(suite, sizeof(*suite));
  96. pj_list_init(&suite->tests);
  97. }
  98. /* Add test case */
  99. PJ_DEF(void) pj_test_suite_add_case(pj_test_suite *suite, pj_test_case *tc)
  100. {
  101. pj_list_push_back(&suite->tests, tc);
  102. }
  103. /* Shuffle */
  104. PJ_DEF(void) pj_test_suite_shuffle(pj_test_suite *suite, int seed)
  105. {
  106. pj_test_case src, *tc;
  107. unsigned total, movable;
  108. if (seed >= 0)
  109. pj_srand(seed);
  110. /* Move tests to new list */
  111. pj_list_init(&src);
  112. pj_list_merge_last(&src, &suite->tests);
  113. /* Move KEEP_FIRST tests first */
  114. for (tc=src.next; tc!=&src; ) {
  115. pj_test_case *next = tc->next;
  116. if (tc->flags & PJ_TEST_KEEP_FIRST) {
  117. pj_list_erase(tc);
  118. pj_list_push_back(&suite->tests, tc);
  119. }
  120. tc = next;
  121. }
  122. /* Count non-KEEP_LAST tests */
  123. for (total=0, movable=0, tc=src.next; tc!=&src; tc=tc->next) {
  124. ++total;
  125. if ((tc->flags & PJ_TEST_KEEP_LAST)==0)
  126. ++movable;
  127. }
  128. /* Shuffle non KEEP_LAST tests */
  129. while (movable > 0) {
  130. int step = pj_rand() % total;
  131. if (step < 0)
  132. continue;
  133. for (tc=src.next; step>0; tc=tc->next, --step)
  134. ;
  135. pj_assert(tc!=&src);
  136. if (tc->flags & PJ_TEST_KEEP_LAST)
  137. continue;
  138. pj_list_erase(tc);
  139. pj_list_push_back(&suite->tests, tc);
  140. --movable;
  141. --total;
  142. }
  143. /* Move KEEP_LAST tests */
  144. for (tc=src.next; tc!=&src; ) {
  145. pj_test_case *next = tc->next;
  146. pj_assert(tc->flags & PJ_TEST_KEEP_LAST);
  147. pj_list_erase(tc);
  148. pj_list_push_back(&suite->tests, tc);
  149. tc = next;
  150. }
  151. }
  152. /* Initialize text runner param with default values */
  153. PJ_DEF(void) pj_test_runner_param_default(pj_test_runner_param *prm)
  154. {
  155. pj_bzero(prm, sizeof(*prm));
  156. #if PJ_HAS_THREADS
  157. prm->nthreads = 1;
  158. #endif
  159. }
  160. /* Main API to start running a test runner */
  161. PJ_DEF(void) pj_test_run(pj_test_runner *runner, pj_test_suite *suite)
  162. {
  163. pj_test_case *tc;
  164. /* Redirect logging to our custom callback */
  165. runner->orig_log_writer = pj_log_get_log_func();
  166. pj_log_set_log_func(&unittest_log_callback);
  167. /* Initialize suite and test cases */
  168. runner->suite = suite;
  169. runner->ntests = (unsigned)pj_list_size(&suite->tests);
  170. runner->nruns = 0;
  171. for (tc=suite->tests.next; tc!=&suite->tests;
  172. tc=tc->next)
  173. {
  174. tc->result = PJ_EPENDING;
  175. tc->runner = NULL; /* WIll be assigned runner when is run */
  176. }
  177. /* Call the run method to perform runner specific loop */
  178. pj_get_timestamp(&suite->start_time);
  179. runner->main(runner);
  180. pj_get_timestamp(&suite->end_time);
  181. /* Restore logging */
  182. pj_log_set_log_func(runner->orig_log_writer);
  183. }
  184. /* Check if we are under test */
  185. PJ_DEF(pj_bool_t) pj_test_is_under_test(void)
  186. {
  187. return pj_log_get_log_func()==&unittest_log_callback;
  188. }
  189. /* Calculate statistics */
  190. PJ_DEF(void) pj_test_get_stat( const pj_test_suite *suite, pj_test_stat *stat)
  191. {
  192. const pj_test_case *tc;
  193. pj_bzero(stat, sizeof(*stat));
  194. stat->duration = pj_elapsed_time(&suite->start_time, &suite->end_time);
  195. stat->ntests = (unsigned)pj_list_size(&suite->tests);
  196. for (tc=suite->tests.next; tc!=&suite->tests; tc=tc->next) {
  197. if (tc->result != PJ_EPENDING) {
  198. stat->nruns++;
  199. if (tc->result != PJ_SUCCESS) {
  200. if (stat->nfailed < PJ_ARRAY_SIZE(stat->failed_names)) {
  201. stat->failed_names[stat->nfailed] = tc->obj_name;
  202. }
  203. stat->nfailed++;
  204. }
  205. }
  206. }
  207. }
  208. /* Display statistics */
  209. PJ_DEF(void) pj_test_display_stat(const pj_test_stat *stat,
  210. const char *test_name,
  211. const char *log_sender)
  212. {
  213. PJ_LOG(3,(log_sender, "Unit test statistics for %s:", test_name));
  214. PJ_LOG(3,(log_sender, " Total number of tests: %d", stat->ntests));
  215. PJ_LOG(3,(log_sender, " Number of test run: %d", stat->nruns));
  216. PJ_LOG(3,(log_sender, " Number of failed test: %d", stat->nfailed));
  217. PJ_LOG(3,(log_sender, " Total duration: %dm%d.%03ds",
  218. (int)stat->duration.sec/60, (int)stat->duration.sec%60,
  219. (int)stat->duration.msec));
  220. }
  221. /* Get name with argument info if any, e.g. "ice_test (arg: 1)" */
  222. static const char *get_test_case_info(const pj_test_case *tc,
  223. char *buf, unsigned size)
  224. {
  225. char arg_info[64];
  226. if (tc->flags & PJ_TEST_FUNC_NO_ARG) {
  227. arg_info[0] = '\0';
  228. } else {
  229. char arg_val[40];
  230. /* treat argument as integer */
  231. pj_ansi_snprintf(arg_val, sizeof(arg_val), "%ld", (long)tc->arg);
  232. /* if arg value is too long (e.g. it's a pointer!), then just show
  233. * a portion of it */
  234. if (pj_ansi_strlen(arg_val) > 6) {
  235. pj_ansi_strxcat(arg_val+6, "...", sizeof(arg_val));
  236. }
  237. pj_ansi_snprintf(arg_info, sizeof(arg_info), " (arg: %s)", arg_val);
  238. }
  239. pj_ansi_snprintf(buf, size, "%s%s", tc->obj_name, arg_info);
  240. return buf;
  241. }
  242. /* Dump previously saved log messages */
  243. PJ_DEF(void) pj_test_display_log_messages(const pj_test_suite *suite,
  244. unsigned flags)
  245. {
  246. const pj_test_case *tc = suite->tests.next;
  247. pj_log_func *log_writer = pj_log_get_log_func();
  248. char tcname[64];
  249. const char *title;
  250. if ((flags & PJ_TEST_ALL_TESTS)==PJ_TEST_ALL_TESTS)
  251. title = "all";
  252. else if ((flags & PJ_TEST_ALL_TESTS)==PJ_TEST_FAILED_TESTS)
  253. title = "failed";
  254. else if ((flags & PJ_TEST_ALL_TESTS)==PJ_TEST_SUCCESSFUL_TESTS)
  255. title = "successful";
  256. else
  257. title = "unknown";
  258. while (tc != &suite->tests) {
  259. const pj_test_log_item *log_item = tc->logs.next;
  260. if ((tc->result == PJ_EPENDING) ||
  261. ((flags & PJ_TEST_ALL_TESTS)==PJ_TEST_FAILED_TESTS &&
  262. tc->result==0) ||
  263. ((flags & PJ_TEST_ALL_TESTS)==PJ_TEST_SUCCESSFUL_TESTS &&
  264. tc->result!=0))
  265. {
  266. /* Test doesn't meet criteria */
  267. tc = tc->next;
  268. continue;
  269. }
  270. if (log_item != &tc->logs) {
  271. if (title && (flags & PJ_TEST_NO_HEADER_FOOTER)==0) {
  272. PJ_LOG(3,(THIS_FILE,
  273. "------------ Displaying %s test logs: ------------",
  274. title));
  275. title = NULL;
  276. }
  277. PJ_LOG(3,(THIS_FILE, "------------ Logs for %s [rc:%d]: ------------",
  278. get_test_case_info(tc, tcname, sizeof(tcname)),
  279. tc->result));
  280. do {
  281. log_writer(log_item->level, log_item->msg, log_item->len);
  282. log_item = log_item->next;
  283. } while (log_item != &tc->logs);
  284. }
  285. tc = tc->next;
  286. }
  287. if (!title) {
  288. PJ_LOG(3,(THIS_FILE,
  289. "--------------------------------------------------------"));
  290. }
  291. }
  292. /* Destroy runner */
  293. PJ_DEF(void) pj_test_runner_destroy(pj_test_runner *runner)
  294. {
  295. runner->destroy(runner);
  296. }
  297. /**************************** Common for runners ****************************/
  298. /* Set the current test case being run by a thread. The logging callback
  299. * needs this info.
  300. */
  301. static void set_current_test_case(pj_test_case *tc)
  302. {
  303. if (tls_id == INVALID_TLS_ID)
  304. tc_main_thread = tc;
  305. else
  306. pj_thread_local_set(tls_id, tc);
  307. }
  308. /* Get the current test case being run by a thread. The logging callback
  309. * needs this info.
  310. */
  311. static pj_test_case *get_current_test_case()
  312. {
  313. if (tls_id == INVALID_TLS_ID)
  314. return tc_main_thread;
  315. else
  316. return (pj_test_case*) pj_thread_local_get(tls_id);
  317. }
  318. /* Logging callback */
  319. static void unittest_log_callback(int level, const char *data, int len)
  320. {
  321. pj_test_case *tc = get_current_test_case();
  322. unsigned req_size, free_size;
  323. pj_bool_t truncated;
  324. pj_test_log_item *log_item;
  325. if (len < 1)
  326. return;
  327. if (tc==NULL) {
  328. /* We are being called by thread that is not part of unit-test.
  329. * Call the original log writer, hoping that the thread did not
  330. * change the writer before this.. (note: this can only be solved
  331. * by setting pj_log_set/get_log_func() to be thread specific.)
  332. */
  333. pj_log_write(level, data, len);
  334. return;
  335. }
  336. /* Filter out unwanted log */
  337. if (level > tc->prm.log_level)
  338. return;
  339. /* If the test case wants to display the original log as they are called,
  340. * then write it using the original logging writer now.
  341. */
  342. if (tc->flags & PJ_TEST_LOG_NO_CACHE) {
  343. tc->runner->orig_log_writer(level, data, len);
  344. return;
  345. }
  346. /* If fifobuf is not configured on this test case, there's nothing
  347. * we can do. We assume tester doesn't want logging.
  348. */
  349. if (pj_fifobuf_capacity(&tc->fb)==0)
  350. return;
  351. /* Required size is the message length plus sizeof(pj_test_log_item).
  352. * This should be enough to save the message INCLUDING the null
  353. * character (because of msg[1] in pj_test_log_item)
  354. */
  355. req_size = len + sizeof(pj_test_log_item);
  356. /* Free the buffer until it's enough to save the message. */
  357. while ((free_size = pj_fifobuf_available_size(&tc->fb)) < req_size &&
  358. !pj_list_empty(&tc->logs))
  359. {
  360. pj_test_log_item *first = tc->logs.next;
  361. /* Free the oldest */
  362. pj_list_erase(first);
  363. pj_fifobuf_free(&tc->fb, first);
  364. }
  365. if (free_size < sizeof(pj_test_log_item) + 10) {
  366. /* Tester has set the fifobuf's size too small */
  367. return;
  368. }
  369. if (free_size < req_size) {
  370. /* Truncate message */
  371. len = free_size - sizeof(pj_test_log_item);
  372. req_size = free_size;
  373. truncated = PJ_TRUE;
  374. } else {
  375. truncated = PJ_FALSE;
  376. }
  377. log_item = (pj_test_log_item*)pj_fifobuf_alloc(&tc->fb, req_size);
  378. PJ_ASSERT_ON_FAIL(log_item, return);
  379. log_item->level = level;
  380. log_item->len = len;
  381. pj_memcpy(log_item->msg, data, len+1);
  382. if (truncated)
  383. log_item->msg[len-1] = '\n';
  384. pj_list_push_back(&tc->logs, log_item);
  385. }
  386. /* Create test case completion line, i.e. the one that looks like:
  387. * [2/24] pool_test [OK]
  388. */
  389. static int get_completion_line( const pj_test_case *tc, const char *end_line,
  390. char *log_buf, unsigned buf_size)
  391. {
  392. char tcname[64];
  393. char res_buf[64];
  394. pj_time_val elapsed;
  395. int log_len;
  396. elapsed = pj_elapsed_time(&tc->start_time, &tc->end_time);
  397. if (tc->result==0) {
  398. pj_ansi_snprintf(res_buf, sizeof(res_buf), "[OK] [%d.%03ds]",
  399. (int)elapsed.sec, (int)elapsed.msec);
  400. } else if (tc->result==PJ_EPENDING) {
  401. pj_ansi_strxcpy(res_buf, "pending", sizeof(res_buf));
  402. } else {
  403. pj_ansi_snprintf(res_buf, sizeof(res_buf), "[Err: %d] [%d.%03ds]",
  404. tc->result, (int)elapsed.sec, (int)elapsed.msec);
  405. }
  406. log_len = pj_ansi_snprintf(log_buf, buf_size, "%-32s %s%s\n",
  407. get_test_case_info(tc, tcname, sizeof(tcname)),
  408. res_buf, end_line);
  409. if (log_len < 1 || log_len >= sizeof(log_buf))
  410. log_len = (int)pj_ansi_strlen(log_buf);
  411. return log_len;
  412. }
  413. /* This is the main function to run a single test case. It may
  414. * be used by the basic runner, which has no threads (=no TLS),
  415. * no fifobuf, no pool, or by multiple threads.
  416. */
  417. static void run_test_case(pj_test_runner *runner, int tid, pj_test_case *tc)
  418. {
  419. char tcname[64];
  420. if (runner->prm.verbosity >= 1) {
  421. const char *exclusivity = (tc->flags & PJ_TEST_EXCLUSIVE) ?
  422. " (exclusive)" : "";
  423. get_test_case_info(tc, tcname, sizeof(tcname));
  424. PJ_LOG(3,(THIS_FILE, "Thread %d starts running %s%s",
  425. tid, tcname, exclusivity));
  426. }
  427. /* Set the test case being worked on by this thread */
  428. set_current_test_case(tc);
  429. tc->runner = runner;
  430. pj_get_timestamp(&tc->start_time);
  431. /* Call the test case's function */
  432. if (tc->flags & PJ_TEST_FUNC_NO_ARG) {
  433. /* Function without argument */
  434. typedef int (*func_t)(void);
  435. func_t func = (func_t)tc->test_func;
  436. tc->result = func();
  437. } else {
  438. tc->result = tc->test_func(tc->arg);
  439. }
  440. if (tc->result == PJ_EPENDING)
  441. tc->result = -12345;
  442. if (tc->result && runner->prm.stop_on_error)
  443. runner->stopping = PJ_TRUE;
  444. pj_get_timestamp(&tc->end_time);
  445. runner->on_test_complete(runner, tc);
  446. /* Reset the test case being worked on by this thread */
  447. set_current_test_case(NULL);
  448. if (runner->prm.verbosity >= 1) {
  449. PJ_LOG(3,(THIS_FILE, "Thread %d done running %s (rc: %d)",
  450. tid, tcname, tc->result));
  451. }
  452. }
  453. static pj_test_case *get_first_running(pj_test_case *tests)
  454. {
  455. pj_test_case *tc;
  456. for (tc=tests->next; tc!=tests; tc=tc->next) {
  457. if (tc->runner && tc->result==PJ_EPENDING)
  458. return tc;
  459. }
  460. return NULL;
  461. }
  462. static pj_test_case *get_next_to_run(pj_test_case *tests)
  463. {
  464. pj_test_case *tc;
  465. for (tc=tests->next; tc!=tests; tc=tc->next) {
  466. if (tc->runner==NULL) {
  467. assert(tc->result==PJ_EPENDING);
  468. return tc;
  469. }
  470. }
  471. return NULL;
  472. }
  473. /******************************* Basic Runner *******************************/
  474. /* This is the "main()" function for basic runner. It just runs the tests
  475. * sequentially
  476. */
  477. static void basic_runner_main(pj_test_runner *runner)
  478. {
  479. pj_test_case *tc;
  480. for (tc = runner->suite->tests.next;
  481. tc != &runner->suite->tests && !runner->stopping;
  482. tc = tc->next)
  483. {
  484. run_test_case(runner, 0, tc);
  485. }
  486. }
  487. /* Basic runner's callback when a test case completes. */
  488. static void basic_on_test_complete(pj_test_runner *runner, pj_test_case *tc)
  489. {
  490. char line[80];
  491. int len;
  492. runner->nruns++;
  493. len = pj_ansi_snprintf( line, sizeof(line), "[%2d/%d] ",
  494. runner->nruns, runner->ntests);
  495. if (len < 1 || len >= sizeof(line))
  496. len = (int)pj_ansi_strlen(line);
  497. len += get_completion_line(tc, "", line+len, sizeof(line)-len);
  498. tc->runner->orig_log_writer(3, line, len);
  499. }
  500. /* Destroy for basic runner */
  501. static void basic_runner_destroy(pj_test_runner *runner)
  502. {
  503. /* Nothing to do for basic runner */
  504. PJ_UNUSED_ARG(runner);
  505. }
  506. /* Initialize a basic runner. */
  507. PJ_DEF(void) pj_test_init_basic_runner(pj_test_runner *runner,
  508. const pj_test_runner_param *prm)
  509. {
  510. pj_bzero(runner, sizeof(*runner));
  511. if (prm)
  512. pj_memcpy(&runner->prm, prm, sizeof(*prm));
  513. else
  514. pj_test_runner_param_default(&runner->prm);
  515. runner->main = &basic_runner_main;
  516. runner->destroy = &basic_runner_destroy;
  517. runner->on_test_complete = &basic_on_test_complete;
  518. }
  519. /******************************* Text Runner *******************************/
  520. typedef struct text_runner_t
  521. {
  522. pj_test_runner base;
  523. pj_mutex_t *mutex;
  524. pj_thread_t **threads;
  525. } text_runner_t;
  526. /* This is called by thread(s) to get the next test case to run.
  527. *
  528. * Returns:
  529. * - PJ_SUCCESS if we successfully returns next test case (tc)
  530. * - PJ_EPENDING if there is tc left but we must wait for completion of
  531. * exclusive tc
  532. * - PJ_ENOTFOUND if there is no further tests, which in this case the
  533. * thread can exit.
  534. * - other error is not anticipated, and will cause thread to exit.
  535. */
  536. static pj_status_t text_runner_get_next_test_case(text_runner_t *runner,
  537. pj_test_case **p_test_case)
  538. {
  539. pj_test_suite *suite;
  540. pj_test_case *cur, *next;
  541. pj_status_t status;
  542. *p_test_case = NULL;
  543. pj_mutex_lock(runner->mutex);
  544. suite = runner->base.suite;
  545. if (runner->base.stopping) {
  546. pj_mutex_unlock(runner->mutex);
  547. return PJ_ENOTFOUND;
  548. }
  549. cur = get_first_running(&suite->tests);
  550. next = get_next_to_run(&suite->tests);
  551. if (cur == NULL) {
  552. if (next==NULL) {
  553. status = PJ_ENOTFOUND;
  554. } else {
  555. *p_test_case = next;
  556. /* Mark as running so it won't get picked up by other threads
  557. * when we exit this function
  558. */
  559. next->runner = &runner->base;
  560. status = PJ_SUCCESS;
  561. }
  562. } else {
  563. /* Test is still running. */
  564. if ((cur->flags & PJ_TEST_EXCLUSIVE)==0 && next != NULL &&
  565. (next->flags & PJ_TEST_EXCLUSIVE)==0)
  566. {
  567. /* Allowed other test to run because test also allows
  568. * parallel test
  569. */
  570. *p_test_case = next;
  571. /* Mark as running so it won't get picked up by other threads
  572. * when we exit this function
  573. */
  574. next->runner = &runner->base;
  575. status = PJ_SUCCESS;
  576. } else {
  577. if (next==NULL) {
  578. /* The current case is the last one. The calling thread
  579. * can quit now.
  580. */
  581. status = PJ_ENOTFOUND;
  582. } else {
  583. /* Current test case or next test do not allow parallel run */
  584. status = PJ_EPENDING;
  585. }
  586. }
  587. }
  588. pj_mutex_unlock(runner->mutex);
  589. return status;
  590. }
  591. typedef struct thread_param_t
  592. {
  593. text_runner_t *runner;
  594. unsigned tid;
  595. } thread_param_t;
  596. /* Thread loop */
  597. static int text_runner_thread_proc(void *arg)
  598. {
  599. thread_param_t *prm = (thread_param_t*)arg;
  600. text_runner_t *runner = prm->runner;
  601. unsigned tid = prm->tid;
  602. for (;;) {
  603. pj_test_case *tc;
  604. pj_status_t status;
  605. status = text_runner_get_next_test_case(runner, &tc);
  606. if (status==PJ_SUCCESS) {
  607. run_test_case(&runner->base, tid, tc);
  608. } else if (status==PJ_EPENDING) {
  609. /* Yeah sleep, but the "correct" solution is probably an order of
  610. * magnitute more complicated, so this is good I think.
  611. */
  612. pj_thread_sleep(PJ_TEST_THREAD_WAIT_MSEC);
  613. } else {
  614. break;
  615. }
  616. }
  617. return 0;
  618. }
  619. /* This is the "main()" function for text runner. */
  620. static void text_runner_main(pj_test_runner *base)
  621. {
  622. text_runner_t *runner = (text_runner_t*)base;
  623. thread_param_t tprm ;
  624. unsigned i;
  625. tprm.runner = runner;
  626. tprm.tid = 0;
  627. for (i=0; i<base->prm.nthreads; ++i) {
  628. pj_thread_resume(runner->threads[i]);
  629. }
  630. /* The main thread behaves like another worker thread */
  631. text_runner_thread_proc(&tprm);
  632. for (i=0; i<base->prm.nthreads; ++i) {
  633. pj_thread_join(runner->threads[i]);
  634. }
  635. }
  636. /* text runner's callback when a test case completes. */
  637. static void text_runner_on_test_complete(pj_test_runner *base,
  638. pj_test_case *tc)
  639. {
  640. text_runner_t *runner = (text_runner_t*)base;
  641. pj_mutex_lock(runner->mutex);
  642. basic_on_test_complete(base, tc);
  643. pj_mutex_unlock(runner->mutex);
  644. }
  645. /* text runner destructor */
  646. static void text_runner_destroy(pj_test_runner *base)
  647. {
  648. text_runner_t *runner = (text_runner_t*)base;
  649. unsigned i;
  650. for (i=0; i<base->prm.nthreads; ++i) {
  651. pj_thread_destroy(runner->threads[i]);
  652. }
  653. if (runner->mutex)
  654. pj_mutex_destroy(runner->mutex);
  655. }
  656. /* Create text runner */
  657. PJ_DEF(pj_status_t) pj_test_create_text_runner(
  658. pj_pool_t *pool,
  659. const pj_test_runner_param *prm,
  660. pj_test_runner **p_runner)
  661. {
  662. text_runner_t *runner;
  663. unsigned i;
  664. pj_status_t status;
  665. *p_runner = NULL;
  666. status = unittest_init();
  667. if (status != PJ_SUCCESS)
  668. return status;
  669. runner = PJ_POOL_ZALLOC_T(pool, text_runner_t);
  670. runner->base.main = text_runner_main;
  671. runner->base.destroy = text_runner_destroy;
  672. runner->base.on_test_complete = &text_runner_on_test_complete;
  673. status = pj_mutex_create(pool, "unittest%p", PJ_MUTEX_RECURSE,
  674. &runner->mutex);
  675. if (status != PJ_SUCCESS)
  676. goto on_error;
  677. if (prm) {
  678. pj_memcpy(&runner->base.prm, prm, sizeof(*prm));
  679. } else {
  680. pj_test_runner_param_default(&runner->base.prm);
  681. }
  682. runner->base.prm.nthreads = 0;
  683. runner->threads = (pj_thread_t**) pj_pool_calloc(pool, prm->nthreads,
  684. sizeof(pj_thread_t*));
  685. for (i=0; i<prm->nthreads; ++i) {
  686. thread_param_t *tprm = PJ_POOL_ZALLOC_T(pool, thread_param_t);
  687. tprm->runner = runner;
  688. tprm->tid = i+1;
  689. status = pj_thread_create(pool, "unittest%p",
  690. text_runner_thread_proc, tprm,
  691. 0, PJ_THREAD_SUSPENDED,
  692. &runner->threads[i]);
  693. if (status != PJ_SUCCESS)
  694. goto on_error;
  695. runner->base.prm.nthreads++;
  696. }
  697. *p_runner = (pj_test_runner*)runner;
  698. return PJ_SUCCESS;
  699. on_error:
  700. text_runner_destroy(&runner->base);
  701. return status;
  702. }