test_taskprocessor.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2012-2013, Digium, Inc.
  5. *
  6. * Mark Michelson <mmichelson@digium.com>
  7. *
  8. * See http://www.asterisk.org for more information about
  9. * the Asterisk project. Please do not directly contact
  10. * any of the maintainers of this project for assistance;
  11. * the project provides a web site, mailing lists and IRC
  12. * channels for your use.
  13. *
  14. * This program is free software, distributed under the terms of
  15. * the GNU General Public License Version 2. See the LICENSE file
  16. * at the top of the source tree.
  17. */
  18. /*!
  19. * \file
  20. * \brief taskprocessor unit tests
  21. *
  22. * \author Mark Michelson <mmichelson@digium.com>
  23. *
  24. */
  25. /*** MODULEINFO
  26. <depend>TEST_FRAMEWORK</depend>
  27. <support_level>core</support_level>
  28. ***/
  29. #include "asterisk.h"
  30. #include "asterisk/test.h"
  31. #include "asterisk/taskprocessor.h"
  32. #include "asterisk/module.h"
  33. #include "asterisk/astobj2.h"
  34. /*!
  35. * \brief userdata associated with baseline taskprocessor test
  36. */
  37. struct task_data {
  38. /* Condition used to signal to queuing thread that task was executed */
  39. ast_cond_t cond;
  40. /* Lock protecting the condition */
  41. ast_mutex_t lock;
  42. /*! Boolean indicating that the task was run */
  43. int task_complete;
  44. };
  45. static void task_data_dtor(void *obj)
  46. {
  47. struct task_data *task_data = obj;
  48. ast_mutex_destroy(&task_data->lock);
  49. ast_cond_destroy(&task_data->cond);
  50. }
  51. /*! \brief Create a task_data object */
  52. static struct task_data *task_data_create(void)
  53. {
  54. struct task_data *task_data =
  55. ao2_alloc(sizeof(*task_data), task_data_dtor);
  56. if (!task_data) {
  57. return NULL;
  58. }
  59. ast_cond_init(&task_data->cond, NULL);
  60. ast_mutex_init(&task_data->lock);
  61. task_data->task_complete = 0;
  62. return task_data;
  63. }
  64. /*!
  65. * \brief Queued task for baseline test.
  66. *
  67. * The task simply sets a boolean to indicate the
  68. * task has been run and then signals a condition
  69. * saying it's complete
  70. */
  71. static int task(void *data)
  72. {
  73. struct task_data *task_data = data;
  74. SCOPED_MUTEX(lock, &task_data->lock);
  75. task_data->task_complete = 1;
  76. ast_cond_signal(&task_data->cond);
  77. return 0;
  78. }
  79. /*!
  80. * \brief Wait for a task to execute.
  81. */
  82. static int task_wait(struct task_data *task_data)
  83. {
  84. struct timeval start = ast_tvnow();
  85. struct timespec end;
  86. SCOPED_MUTEX(lock, &task_data->lock);
  87. end.tv_sec = start.tv_sec + 30;
  88. end.tv_nsec = start.tv_usec * 1000;
  89. while (!task_data->task_complete) {
  90. int res;
  91. res = ast_cond_timedwait(&task_data->cond, &task_data->lock,
  92. &end);
  93. if (res == ETIMEDOUT) {
  94. return -1;
  95. }
  96. }
  97. return 0;
  98. }
  99. /*!
  100. * \brief Baseline test for default taskprocessor
  101. *
  102. * This test ensures that when a task is added to a taskprocessor that
  103. * has been allocated with a default listener that the task gets executed
  104. * as expected
  105. */
  106. AST_TEST_DEFINE(default_taskprocessor)
  107. {
  108. RAII_VAR(struct ast_taskprocessor *, tps, NULL, ast_taskprocessor_unreference);
  109. RAII_VAR(struct task_data *, task_data, NULL, ao2_cleanup);
  110. int res;
  111. switch (cmd) {
  112. case TEST_INIT:
  113. info->name = "default_taskprocessor";
  114. info->category = "/main/taskprocessor/";
  115. info->summary = "Test of default taskproccesor";
  116. info->description =
  117. "Ensures that a queued task gets executed.";
  118. return AST_TEST_NOT_RUN;
  119. case TEST_EXECUTE:
  120. break;
  121. }
  122. tps = ast_taskprocessor_get("test", TPS_REF_DEFAULT);
  123. if (!tps) {
  124. ast_test_status_update(test, "Unable to create test taskprocessor\n");
  125. return AST_TEST_FAIL;
  126. }
  127. task_data = task_data_create();
  128. if (!task_data) {
  129. ast_test_status_update(test, "Unable to create task_data\n");
  130. return AST_TEST_FAIL;
  131. }
  132. ast_taskprocessor_push(tps, task, task_data);
  133. res = task_wait(task_data);
  134. if (res != 0) {
  135. ast_test_status_update(test, "Queued task did not execute!\n");
  136. return AST_TEST_FAIL;
  137. }
  138. return AST_TEST_PASS;
  139. }
  140. #define NUM_TASKS 20000
  141. /*!
  142. * \brief Relevant data associated with taskprocessor load test
  143. */
  144. static struct load_task_data {
  145. /*! Condition used to indicate a task has completed executing */
  146. ast_cond_t cond;
  147. /*! Lock used to protect the condition */
  148. ast_mutex_t lock;
  149. /*! Counter of the number of completed tasks */
  150. int tasks_completed;
  151. /*! Storage for task-specific data */
  152. int task_rand[NUM_TASKS];
  153. } load_task_results;
  154. /*!
  155. * \brief a queued task to be used in the taskprocessor load test
  156. *
  157. * The task increments the number of tasks executed and puts the passed-in
  158. * data into the next slot in the array of random data.
  159. */
  160. static int load_task(void *data)
  161. {
  162. int *randdata = data;
  163. SCOPED_MUTEX(lock, &load_task_results.lock);
  164. load_task_results.task_rand[load_task_results.tasks_completed++] = *randdata;
  165. ast_cond_signal(&load_task_results.cond);
  166. return 0;
  167. }
  168. /*!
  169. * \brief Load test for taskprocessor with default listener
  170. *
  171. * This test queues a large number of tasks, each with random data associated.
  172. * The test ensures that all of the tasks are run and that the tasks are executed
  173. * in the same order that they were queued
  174. */
  175. AST_TEST_DEFINE(default_taskprocessor_load)
  176. {
  177. struct ast_taskprocessor *tps;
  178. struct timeval start;
  179. struct timespec ts;
  180. enum ast_test_result_state res = AST_TEST_PASS;
  181. int timedwait_res;
  182. int i;
  183. int rand_data[NUM_TASKS];
  184. switch (cmd) {
  185. case TEST_INIT:
  186. info->name = "default_taskprocessor_load";
  187. info->category = "/main/taskprocessor/";
  188. info->summary = "Load test of default taskproccesor";
  189. info->description =
  190. "Ensure that a large number of queued tasks are executed in the proper order.";
  191. return AST_TEST_NOT_RUN;
  192. case TEST_EXECUTE:
  193. break;
  194. }
  195. tps = ast_taskprocessor_get("test", TPS_REF_DEFAULT);
  196. if (!tps) {
  197. ast_test_status_update(test, "Unable to create test taskprocessor\n");
  198. return AST_TEST_FAIL;
  199. }
  200. start = ast_tvnow();
  201. ts.tv_sec = start.tv_sec + 60;
  202. ts.tv_nsec = start.tv_usec * 1000;
  203. ast_cond_init(&load_task_results.cond, NULL);
  204. ast_mutex_init(&load_task_results.lock);
  205. load_task_results.tasks_completed = 0;
  206. for (i = 0; i < NUM_TASKS; ++i) {
  207. rand_data[i] = ast_random();
  208. ast_taskprocessor_push(tps, load_task, &rand_data[i]);
  209. }
  210. ast_mutex_lock(&load_task_results.lock);
  211. while (load_task_results.tasks_completed < NUM_TASKS) {
  212. timedwait_res = ast_cond_timedwait(&load_task_results.cond, &load_task_results.lock, &ts);
  213. if (timedwait_res == ETIMEDOUT) {
  214. break;
  215. }
  216. }
  217. ast_mutex_unlock(&load_task_results.lock);
  218. if (load_task_results.tasks_completed != NUM_TASKS) {
  219. ast_test_status_update(test, "Unexpected number of tasks executed. Expected %d but got %d\n",
  220. NUM_TASKS, load_task_results.tasks_completed);
  221. res = AST_TEST_FAIL;
  222. goto test_end;
  223. }
  224. for (i = 0; i < NUM_TASKS; ++i) {
  225. if (rand_data[i] != load_task_results.task_rand[i]) {
  226. ast_test_status_update(test, "Queued tasks did not execute in order\n");
  227. res = AST_TEST_FAIL;
  228. goto test_end;
  229. }
  230. }
  231. test_end:
  232. tps = ast_taskprocessor_unreference(tps);
  233. ast_mutex_destroy(&load_task_results.lock);
  234. ast_cond_destroy(&load_task_results.cond);
  235. return res;
  236. }
  237. /*!
  238. * \brief Private data for the test taskprocessor listener
  239. */
  240. struct test_listener_pvt {
  241. /* Counter of number of tasks pushed to the queue */
  242. int num_pushed;
  243. /* Counter of number of times the queue was emptied */
  244. int num_emptied;
  245. /* Counter of number of times that a pushed task occurred on an empty queue */
  246. int num_was_empty;
  247. /* Boolean indicating whether the shutdown callback was called */
  248. int shutdown;
  249. };
  250. /*!
  251. * \brief test taskprocessor listener's alloc callback
  252. */
  253. static void *test_listener_pvt_alloc(void)
  254. {
  255. struct test_listener_pvt *pvt;
  256. pvt = ast_calloc(1, sizeof(*pvt));
  257. return pvt;
  258. }
  259. /*!
  260. * \brief test taskprocessor listener's start callback
  261. */
  262. static int test_start(struct ast_taskprocessor_listener *listener)
  263. {
  264. return 0;
  265. }
  266. /*!
  267. * \brief test taskprocessor listener's task_pushed callback
  268. *
  269. * Adjusts private data's stats as indicated by the parameters.
  270. */
  271. static void test_task_pushed(struct ast_taskprocessor_listener *listener, int was_empty)
  272. {
  273. struct test_listener_pvt *pvt = ast_taskprocessor_listener_get_user_data(listener);
  274. ++pvt->num_pushed;
  275. if (was_empty) {
  276. ++pvt->num_was_empty;
  277. }
  278. }
  279. /*!
  280. * \brief test taskprocessor listener's emptied callback.
  281. */
  282. static void test_emptied(struct ast_taskprocessor_listener *listener)
  283. {
  284. struct test_listener_pvt *pvt = ast_taskprocessor_listener_get_user_data(listener);
  285. ++pvt->num_emptied;
  286. }
  287. /*!
  288. * \brief test taskprocessor listener's shutdown callback.
  289. */
  290. static void test_shutdown(struct ast_taskprocessor_listener *listener)
  291. {
  292. struct test_listener_pvt *pvt = ast_taskprocessor_listener_get_user_data(listener);
  293. pvt->shutdown = 1;
  294. }
  295. static const struct ast_taskprocessor_listener_callbacks test_callbacks = {
  296. .start = test_start,
  297. .task_pushed = test_task_pushed,
  298. .emptied = test_emptied,
  299. .shutdown = test_shutdown,
  300. };
  301. /*!
  302. * \brief Queued task for taskprocessor listener test.
  303. *
  304. * Does nothing.
  305. */
  306. static int listener_test_task(void *ignore)
  307. {
  308. return 0;
  309. }
  310. /*!
  311. * \brief helper to ensure that statistics the listener is keeping are what we expect
  312. *
  313. * \param test The currently-running test
  314. * \param pvt The private data for the taskprocessor listener
  315. * \param num_pushed The expected current number of tasks pushed to the processor
  316. * \param num_emptied The expected current number of times the taskprocessor has become empty
  317. * \param num_was_empty The expected current number of times that tasks were pushed to an empty taskprocessor
  318. * \retval -1 Stats were not as expected
  319. * \retval 0 Stats were as expected
  320. */
  321. static int check_stats(struct ast_test *test, const struct test_listener_pvt *pvt, int num_pushed, int num_emptied, int num_was_empty)
  322. {
  323. if (pvt->num_pushed != num_pushed) {
  324. ast_test_status_update(test, "Unexpected number of tasks pushed. Expected %d but got %d\n",
  325. num_pushed, pvt->num_pushed);
  326. return -1;
  327. }
  328. if (pvt->num_emptied != num_emptied) {
  329. ast_test_status_update(test, "Unexpected number of empties. Expected %d but got %d\n",
  330. num_emptied, pvt->num_emptied);
  331. return -1;
  332. }
  333. if (pvt->num_was_empty != num_was_empty) {
  334. ast_test_status_update(test, "Unexpected number of empties. Expected %d but got %d\n",
  335. num_was_empty, pvt->num_emptied);
  336. return -1;
  337. }
  338. return 0;
  339. }
  340. /*!
  341. * \brief Test for a taskprocessor with custom listener.
  342. *
  343. * This test pushes tasks to a taskprocessor with a custom listener, executes the taskss,
  344. * and destroys the taskprocessor.
  345. *
  346. * The test ensures that the listener's callbacks are called when expected and that the data
  347. * being passed in is accurate.
  348. */
  349. AST_TEST_DEFINE(taskprocessor_listener)
  350. {
  351. struct ast_taskprocessor *tps = NULL;
  352. struct ast_taskprocessor_listener *listener = NULL;
  353. struct test_listener_pvt *pvt = NULL;
  354. enum ast_test_result_state res = AST_TEST_PASS;
  355. switch (cmd) {
  356. case TEST_INIT:
  357. info->name = "taskprocessor_listener";
  358. info->category = "/main/taskprocessor/";
  359. info->summary = "Test of taskproccesor listeners";
  360. info->description =
  361. "Ensures that listener callbacks are called when expected.";
  362. return AST_TEST_NOT_RUN;
  363. case TEST_EXECUTE:
  364. break;
  365. }
  366. pvt = test_listener_pvt_alloc();
  367. if (!pvt) {
  368. ast_test_status_update(test, "Unable to allocate test taskprocessor listener user data\n");
  369. return AST_TEST_FAIL;
  370. }
  371. listener = ast_taskprocessor_listener_alloc(&test_callbacks, pvt);
  372. if (!listener) {
  373. ast_test_status_update(test, "Unable to allocate test taskprocessor listener\n");
  374. res = AST_TEST_FAIL;
  375. goto test_exit;
  376. }
  377. tps = ast_taskprocessor_create_with_listener("test_listener", listener);
  378. if (!tps) {
  379. ast_test_status_update(test, "Unable to allocate test taskprocessor\n");
  380. res = AST_TEST_FAIL;
  381. goto test_exit;
  382. }
  383. ast_taskprocessor_push(tps, listener_test_task, NULL);
  384. if (check_stats(test, pvt, 1, 0, 1) < 0) {
  385. res = AST_TEST_FAIL;
  386. goto test_exit;
  387. }
  388. ast_taskprocessor_push(tps, listener_test_task, NULL);
  389. if (check_stats(test, pvt, 2, 0, 1) < 0) {
  390. res = AST_TEST_FAIL;
  391. goto test_exit;
  392. }
  393. ast_taskprocessor_execute(tps);
  394. if (check_stats(test, pvt, 2, 0, 1) < 0) {
  395. res = AST_TEST_FAIL;
  396. goto test_exit;
  397. }
  398. ast_taskprocessor_execute(tps);
  399. if (check_stats(test, pvt, 2, 1, 1) < 0) {
  400. res = AST_TEST_FAIL;
  401. goto test_exit;
  402. }
  403. tps = ast_taskprocessor_unreference(tps);
  404. if (!pvt->shutdown) {
  405. res = AST_TEST_FAIL;
  406. goto test_exit;
  407. }
  408. test_exit:
  409. ao2_cleanup(listener);
  410. /* This is safe even if tps is NULL */
  411. ast_taskprocessor_unreference(tps);
  412. ast_free(pvt);
  413. return res;
  414. }
  415. struct shutdown_data {
  416. ast_cond_t in;
  417. ast_cond_t out;
  418. ast_mutex_t lock;
  419. int task_complete;
  420. int task_started;
  421. int task_stop_waiting;
  422. };
  423. static void shutdown_data_dtor(void *data)
  424. {
  425. struct shutdown_data *shutdown_data = data;
  426. ast_mutex_destroy(&shutdown_data->lock);
  427. ast_cond_destroy(&shutdown_data->in);
  428. ast_cond_destroy(&shutdown_data->out);
  429. }
  430. static struct shutdown_data *shutdown_data_create(int dont_wait)
  431. {
  432. RAII_VAR(struct shutdown_data *, shutdown_data, NULL, ao2_cleanup);
  433. shutdown_data = ao2_alloc(sizeof(*shutdown_data), shutdown_data_dtor);
  434. if (!shutdown_data) {
  435. return NULL;
  436. }
  437. ast_mutex_init(&shutdown_data->lock);
  438. ast_cond_init(&shutdown_data->in, NULL);
  439. ast_cond_init(&shutdown_data->out, NULL);
  440. shutdown_data->task_stop_waiting = dont_wait;
  441. ao2_ref(shutdown_data, +1);
  442. return shutdown_data;
  443. }
  444. static int shutdown_task_exec(void *data)
  445. {
  446. struct shutdown_data *shutdown_data = data;
  447. SCOPED_MUTEX(lock, &shutdown_data->lock);
  448. shutdown_data->task_started = 1;
  449. ast_cond_signal(&shutdown_data->out);
  450. while (!shutdown_data->task_stop_waiting) {
  451. ast_cond_wait(&shutdown_data->in, &shutdown_data->lock);
  452. }
  453. shutdown_data->task_complete = 1;
  454. ast_cond_signal(&shutdown_data->out);
  455. return 0;
  456. }
  457. static int shutdown_waitfor_completion(struct shutdown_data *shutdown_data)
  458. {
  459. struct timeval start = ast_tvnow();
  460. struct timespec end = {
  461. .tv_sec = start.tv_sec + 5,
  462. .tv_nsec = start.tv_usec * 1000
  463. };
  464. SCOPED_MUTEX(lock, &shutdown_data->lock);
  465. while (!shutdown_data->task_complete) {
  466. if (ast_cond_timedwait(&shutdown_data->out, &shutdown_data->lock, &end) == ETIMEDOUT) {
  467. break;
  468. }
  469. }
  470. return shutdown_data->task_complete;
  471. }
  472. static int shutdown_has_completed(struct shutdown_data *shutdown_data)
  473. {
  474. SCOPED_MUTEX(lock, &shutdown_data->lock);
  475. return shutdown_data->task_complete;
  476. }
  477. static int shutdown_waitfor_start(struct shutdown_data *shutdown_data)
  478. {
  479. struct timeval start = ast_tvnow();
  480. struct timespec end = {
  481. .tv_sec = start.tv_sec + 5,
  482. .tv_nsec = start.tv_usec * 1000
  483. };
  484. SCOPED_MUTEX(lock, &shutdown_data->lock);
  485. while (!shutdown_data->task_started) {
  486. if (ast_cond_timedwait(&shutdown_data->out, &shutdown_data->lock, &end) == ETIMEDOUT) {
  487. break;
  488. }
  489. }
  490. return shutdown_data->task_started;
  491. }
  492. static void shutdown_poke(struct shutdown_data *shutdown_data)
  493. {
  494. SCOPED_MUTEX(lock, &shutdown_data->lock);
  495. shutdown_data->task_stop_waiting = 1;
  496. ast_cond_signal(&shutdown_data->in);
  497. }
  498. static void *tps_shutdown_thread(void *data)
  499. {
  500. struct ast_taskprocessor *tps = data;
  501. ast_taskprocessor_unreference(tps);
  502. return NULL;
  503. }
  504. AST_TEST_DEFINE(taskprocessor_shutdown)
  505. {
  506. RAII_VAR(struct ast_taskprocessor *, tps, NULL, ast_taskprocessor_unreference);
  507. RAII_VAR(struct shutdown_data *, task1, NULL, ao2_cleanup);
  508. RAII_VAR(struct shutdown_data *, task2, NULL, ao2_cleanup);
  509. int push_res;
  510. int wait_res;
  511. int pthread_res;
  512. pthread_t shutdown_thread;
  513. switch (cmd) {
  514. case TEST_INIT:
  515. info->name = "taskprocessor_shutdown";
  516. info->category = "/main/taskprocessor/";
  517. info->summary = "Test of taskproccesor shutdown sequence";
  518. info->description =
  519. "Ensures that all tasks run to completion after the taskprocessor has been unref'ed.";
  520. return AST_TEST_NOT_RUN;
  521. case TEST_EXECUTE:
  522. break;
  523. }
  524. tps = ast_taskprocessor_get("test_shutdown", TPS_REF_DEFAULT);
  525. task1 = shutdown_data_create(0); /* task1 waits to be poked */
  526. task2 = shutdown_data_create(1); /* task2 waits for nothing */
  527. if (!tps || !task1 || !task2) {
  528. ast_test_status_update(test, "Allocation error\n");
  529. return AST_TEST_FAIL;
  530. }
  531. push_res = ast_taskprocessor_push(tps, shutdown_task_exec, task1);
  532. if (push_res != 0) {
  533. ast_test_status_update(test, "Could not push task1\n");
  534. return AST_TEST_FAIL;
  535. }
  536. push_res = ast_taskprocessor_push(tps, shutdown_task_exec, task2);
  537. if (push_res != 0) {
  538. ast_test_status_update(test, "Could not push task2\n");
  539. return AST_TEST_FAIL;
  540. }
  541. wait_res = shutdown_waitfor_start(task1);
  542. if (!wait_res) {
  543. ast_test_status_update(test, "Task1 didn't start\n");
  544. return AST_TEST_FAIL;
  545. }
  546. pthread_res = ast_pthread_create(&shutdown_thread, NULL, tps_shutdown_thread, tps);
  547. if (pthread_res != 0) {
  548. ast_test_status_update(test, "Failed to create shutdown thread\n");
  549. return AST_TEST_FAIL;
  550. }
  551. tps = NULL;
  552. /* Wakeup task1; it should complete */
  553. shutdown_poke(task1);
  554. wait_res = shutdown_waitfor_completion(task1);
  555. if (!wait_res) {
  556. ast_test_status_update(test, "Task1 didn't complete\n");
  557. return AST_TEST_FAIL;
  558. }
  559. /* Wait for shutdown to complete */
  560. pthread_join(shutdown_thread, NULL);
  561. /* Should have also also completed task2 */
  562. wait_res = shutdown_has_completed(task2);
  563. if (!wait_res) {
  564. ast_test_status_update(test, "Task2 didn't finish\n");
  565. return AST_TEST_FAIL;
  566. }
  567. return AST_TEST_PASS;
  568. }
  569. static int local_task_exe(struct ast_taskprocessor_local *local)
  570. {
  571. int *local_data = local->local_data;
  572. struct task_data *task_data = local->data;
  573. *local_data = 1;
  574. task(task_data);
  575. return 0;
  576. }
  577. AST_TEST_DEFINE(taskprocessor_push_local)
  578. {
  579. RAII_VAR(struct ast_taskprocessor *, tps, NULL,
  580. ast_taskprocessor_unreference);
  581. struct task_data *task_data;
  582. int local_data;
  583. int res;
  584. switch (cmd) {
  585. case TEST_INIT:
  586. info->name = __func__;
  587. info->category = "/main/taskprocessor/";
  588. info->summary = "Test of pushing local data";
  589. info->description =
  590. "Ensures that local data is passed along.";
  591. return AST_TEST_NOT_RUN;
  592. case TEST_EXECUTE:
  593. break;
  594. }
  595. tps = ast_taskprocessor_get("test", TPS_REF_DEFAULT);
  596. if (!tps) {
  597. ast_test_status_update(test, "Unable to create test taskprocessor\n");
  598. return AST_TEST_FAIL;
  599. }
  600. task_data = task_data_create();
  601. if (!task_data) {
  602. ast_test_status_update(test, "Unable to create task_data\n");
  603. return AST_TEST_FAIL;
  604. }
  605. local_data = 0;
  606. ast_taskprocessor_set_local(tps, &local_data);
  607. ast_taskprocessor_push_local(tps, local_task_exe, task_data);
  608. res = task_wait(task_data);
  609. if (res != 0) {
  610. ast_test_status_update(test, "Queued task did not execute!\n");
  611. return AST_TEST_FAIL;
  612. }
  613. if (local_data != 1) {
  614. ast_test_status_update(test,
  615. "Queued task did not set local_data!\n");
  616. return AST_TEST_FAIL;
  617. }
  618. return AST_TEST_PASS;
  619. }
  620. static int unload_module(void)
  621. {
  622. ast_test_unregister(default_taskprocessor);
  623. ast_test_unregister(default_taskprocessor_load);
  624. ast_test_unregister(taskprocessor_listener);
  625. ast_test_unregister(taskprocessor_shutdown);
  626. ast_test_unregister(taskprocessor_push_local);
  627. return 0;
  628. }
  629. static int load_module(void)
  630. {
  631. ast_test_register(default_taskprocessor);
  632. ast_test_register(default_taskprocessor_load);
  633. ast_test_register(taskprocessor_listener);
  634. ast_test_register(taskprocessor_shutdown);
  635. ast_test_register(taskprocessor_push_local);
  636. return AST_MODULE_LOAD_SUCCESS;
  637. }
  638. AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "taskprocessor test module");