sqlite_test.cc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  1. /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
  2. *
  3. * Gearmand client and server library.
  4. *
  5. * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
  6. * Copyright (C) 2008 Brian Aker, Eric Day
  7. * All rights reserved.
  8. *
  9. * Redistribution and use in source and binary forms, with or without
  10. * modification, are permitted provided that the following conditions are
  11. * met:
  12. *
  13. * * Redistributions of source code must retain the above copyright
  14. * notice, this list of conditions and the following disclaimer.
  15. *
  16. * * Redistributions in binary form must reproduce the above
  17. * copyright notice, this list of conditions and the following disclaimer
  18. * in the documentation and/or other materials provided with the
  19. * distribution.
  20. *
  21. * * The names of its contributors may not be used to endorse or
  22. * promote products derived from this software without specific prior
  23. * written permission.
  24. *
  25. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  26. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  27. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  28. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  29. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  30. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  31. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  32. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  33. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  34. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  35. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  36. *
  37. */
  38. #include "gear_config.h"
  39. #include <libtest/test.hpp>
  40. #include <sqlite3.h>
  41. using namespace libtest;
  42. #include <cassert>
  43. #include <cstdio>
  44. #include <cstdlib>
  45. #include <cstring>
  46. #include <unistd.h>
  47. #include <libgearman/gearman.h>
  48. #define GEARMAN_QUEUE_SQLITE_DEFAULT_TABLE "gearman_queue"
  49. #include <tests/basic.h>
  50. #include <tests/context.h>
  51. #include "libgearman/client.hpp"
  52. #include "libgearman/worker.hpp"
  53. using namespace org::gearmand;
  54. #include "tests/workers/v2/called.h"
  55. #include <climits>
  56. // Prototypes
  57. #ifndef __INTEL_COMPILER
  58. #pragma GCC diagnostic ignored "-Wold-style-cast"
  59. #endif
  60. static int sql_print(void *, int argc, char **argv, char **)
  61. {
  62. (void)argc;
  63. (void)argv;
  64. assert(argc == 2);
  65. return 0;
  66. }
  67. static int sql_count(void * rows_, int argc, char **argv, char **)
  68. {
  69. if (argc)
  70. {
  71. int *rows= (int*)rows_;
  72. *rows= atoi(argv[0]);
  73. }
  74. return 0;
  75. }
  76. class Sqlite {
  77. public:
  78. Sqlite(const std::string& schema_)
  79. {
  80. if (sqlite3_open(schema_.c_str(), &_db) != SQLITE_OK)
  81. {
  82. FAIL(sqlite3_errmsg(_db));
  83. }
  84. sqlite3_busy_timeout(_db, 6000);
  85. }
  86. ~Sqlite()
  87. {
  88. if (_db)
  89. {
  90. sqlite3_close(_db);
  91. _db= NULL;
  92. }
  93. }
  94. int vcount()
  95. {
  96. reset_error();
  97. std::string count_query;
  98. count_query+= "SELECT count(*) FROM ";
  99. count_query+= GEARMAN_QUEUE_SQLITE_DEFAULT_TABLE;
  100. int rows= 0;
  101. char *err= NULL;
  102. sqlite3_exec(_db, count_query.c_str(), sql_count, &rows, &err);
  103. if (err != NULL)
  104. {
  105. _error_string= err;
  106. sqlite3_free(err);
  107. return -1;
  108. }
  109. return rows;
  110. }
  111. void vprint_unique()
  112. {
  113. reset_error();
  114. std::string count_query;
  115. count_query+= "SELECT unique_key, function_name FROM ";
  116. count_query+= GEARMAN_QUEUE_SQLITE_DEFAULT_TABLE;
  117. char *err= NULL;
  118. sqlite3_exec(_db, count_query.c_str(), sql_print, NULL, &err);
  119. if (err != NULL)
  120. {
  121. _error_string= err;
  122. sqlite3_free(err);
  123. }
  124. }
  125. bool has_error()
  126. {
  127. return _error_string.size();
  128. }
  129. const std::string& error_string()
  130. {
  131. return _error_string;
  132. }
  133. protected:
  134. void reset_error()
  135. {
  136. _error_string.clear();
  137. }
  138. std::string _error_string;
  139. private:
  140. sqlite3 *_db;
  141. };
  142. #pragma GCC diagnostic push
  143. #pragma GCC diagnostic ignored "-Wunreachable-code"
  144. static bool test_for_HAVE_LIBSQLITE3()
  145. {
  146. if (HAVE_LIBSQLITE3)
  147. {
  148. return true;
  149. }
  150. return false;
  151. }
  152. #pragma GCC diagnostic pop
  153. static test_return_t gearmand_basic_option_test(void *)
  154. {
  155. const char *args[]= { "--check-args",
  156. "--queue-type=libsqlite3",
  157. "--libsqlite3-db=var/tmp/gearman.sql",
  158. "--libsqlite3-table=custom_table",
  159. 0 };
  160. ASSERT_EQ(EXIT_SUCCESS, exec_cmdline(gearmand_binary(), args, true));
  161. return TEST_SUCCESS;
  162. }
  163. static test_return_t gearmand_basic_option_without_table_test(void *)
  164. {
  165. std::string sql_file= libtest::create_tmpfile("sqlite");
  166. char sql_buffer[1024];
  167. snprintf(sql_buffer, sizeof(sql_buffer), "--libsqlite3-db=%.*s", int(sql_file.length()), sql_file.c_str());
  168. const char *args[]= { "--check-args",
  169. "--queue-type=libsqlite3",
  170. sql_buffer,
  171. 0 };
  172. ASSERT_EQ(EXIT_SUCCESS, exec_cmdline(gearmand_binary(), args, true));
  173. ASSERT_EQ(-1, access(sql_file.c_str(), R_OK | W_OK ));
  174. return TEST_SUCCESS;
  175. }
  176. static test_return_t gearmand_basic_option_shutdown_queue_TEST(void *)
  177. {
  178. std::string sql_file= libtest::create_tmpfile("sqlite");
  179. char sql_buffer[1024];
  180. snprintf(sql_buffer, sizeof(sql_buffer), "--libsqlite3-db=%.*s", int(sql_file.length()), sql_file.c_str());
  181. const char *args[]= { "--check-args",
  182. "--queue-type=libsqlite3",
  183. sql_buffer,
  184. "--store-queue-on-shutdown",
  185. 0 };
  186. test_compare(EXIT_SUCCESS, exec_cmdline(gearmand_binary(), args, true));
  187. test_compare(-1, access(sql_file.c_str(), R_OK | W_OK ));
  188. return TEST_SUCCESS;
  189. }
  190. static test_return_t collection_init(void *object)
  191. {
  192. std::string sql_file= libtest::create_tmpfile("sqlite");
  193. char sql_buffer[1024];
  194. snprintf(sql_buffer, sizeof(sql_buffer), "--libsqlite3-db=%.*s", int(sql_file.length()), sql_file.c_str());
  195. const char *argv[]= {
  196. "--queue-type=libsqlite3",
  197. sql_buffer,
  198. 0 };
  199. Context *test= (Context *)object;
  200. ASSERT_TRUE(test);
  201. test->reset();
  202. ASSERT_TRUE(test->initialize(argv));
  203. ASSERT_EQ(0, access(sql_file.c_str(), R_OK | W_OK ));
  204. test->extra_file(sql_file.c_str());
  205. std::string sql_journal_file(sql_file);
  206. sql_journal_file+= "-journal";
  207. test->extra_file(sql_journal_file);
  208. return TEST_SUCCESS;
  209. }
  210. static test_return_t collection_cleanup(void *object)
  211. {
  212. Context *test= (Context *)object;
  213. test->reset();
  214. return TEST_SUCCESS;
  215. }
  216. static test_return_t lp_1087654_TEST(void* object)
  217. {
  218. Context *test= (Context *)object;
  219. server_startup_st &servers= test->_servers;
  220. const int32_t inserted_jobs= 8;
  221. std::string sql_file= libtest::create_tmpfile("sqlite");
  222. Sqlite sql_handle(sql_file);
  223. char sql_buffer[1024];
  224. snprintf(sql_buffer, sizeof(sql_buffer), "--libsqlite3-db=%.*s", int(sql_file.length()), sql_file.c_str());
  225. const char *argv[]= {
  226. "--queue-type=libsqlite3",
  227. sql_buffer,
  228. "--store-queue-on-shutdown",
  229. 0 };
  230. {
  231. in_port_t first_port= libtest::get_free_port();
  232. ASSERT_TRUE(server_startup(servers, "gearmand", first_port, argv));
  233. test_compare(0, access(sql_file.c_str(), R_OK | W_OK ));
  234. {
  235. libgearman::Worker worker(first_port);
  236. test_compare(gearman_worker_register(&worker, __func__, 0), GEARMAN_SUCCESS);
  237. }
  238. {
  239. libgearman::Client client(first_port);
  240. gearman_job_handle_t job_handle;
  241. for (int32_t x= 0; x < inserted_jobs; ++x)
  242. {
  243. switch (random() % 3)
  244. {
  245. case 0:
  246. test_compare(gearman_client_do_background(&client,
  247. __func__, // func
  248. NULL, // unique
  249. test_literal_param("foo"),
  250. job_handle), GEARMAN_SUCCESS);
  251. break;
  252. case 1:
  253. test_compare(gearman_client_do_low_background(&client,
  254. __func__, // func
  255. NULL, // unique
  256. test_literal_param("fudge"),
  257. job_handle), GEARMAN_SUCCESS);
  258. break;
  259. default:
  260. case 2:
  261. test_compare(gearman_client_do_high_background(&client,
  262. __func__, // func
  263. NULL, // unique
  264. test_literal_param("history"),
  265. job_handle), GEARMAN_SUCCESS);
  266. break;
  267. }
  268. }
  269. }
  270. // Before we shutdown we need to see if anything is sitting in the queue
  271. {
  272. if (sql_handle.vcount() != 0)
  273. {
  274. if (sql_handle.has_error())
  275. {
  276. Error << sql_handle.error_string();
  277. }
  278. else
  279. {
  280. Out << "sql_handle.vprint_unique()";
  281. sql_handle.vprint_unique();
  282. }
  283. }
  284. test_zero(sql_handle.vcount());
  285. }
  286. servers.clear();
  287. }
  288. // After shutdown we need to see that the queue was storage
  289. {
  290. if (sql_handle.vcount() != inserted_jobs)
  291. {
  292. if (sql_handle.has_error())
  293. {
  294. Error << sql_handle.error_string();
  295. }
  296. else
  297. {
  298. Out << "sql_handle.vprint_unique()";
  299. sql_handle.vprint_unique();
  300. }
  301. }
  302. test_compare(sql_handle.vcount(), inserted_jobs);
  303. }
  304. test_compare(0, access(sql_file.c_str(), R_OK | W_OK ));
  305. {
  306. in_port_t first_port= libtest::get_free_port();
  307. ASSERT_TRUE(server_startup(servers, "gearmand", first_port, argv));
  308. {
  309. libgearman::Worker worker(first_port);
  310. Called called;
  311. gearman_function_t counter_function= gearman_function_create(called_worker);
  312. test_compare(gearman_worker_define_function(&worker,
  313. test_literal_param(__func__),
  314. counter_function,
  315. 3000, &called), GEARMAN_SUCCESS);
  316. const int32_t max_timeout= 4;
  317. int32_t max_timeout_value= max_timeout;
  318. int32_t job_count= 0;
  319. gearman_return_t ret;
  320. do
  321. {
  322. ret= gearman_worker_work(&worker);
  323. if (gearman_success(ret))
  324. {
  325. job_count++;
  326. max_timeout_value= max_timeout;
  327. if (job_count == inserted_jobs)
  328. {
  329. break;
  330. }
  331. }
  332. else if (ret == GEARMAN_TIMEOUT)
  333. {
  334. Error << " hit timeout";
  335. if ((--max_timeout_value) < 0)
  336. {
  337. break;
  338. }
  339. }
  340. } while (ret == GEARMAN_TIMEOUT or ret == GEARMAN_SUCCESS);
  341. test_compare(called.count(), inserted_jobs);
  342. }
  343. servers.clear();
  344. }
  345. {
  346. if (sql_handle.vcount() != 0)
  347. {
  348. Error << "make";
  349. if (sql_handle.has_error())
  350. {
  351. Error << sql_handle.error_string();
  352. }
  353. else
  354. {
  355. Out << "sql_handle.vprint_unique()";
  356. sql_handle.vprint_unique();
  357. }
  358. }
  359. test_zero(sql_handle.vcount());
  360. }
  361. return TEST_SUCCESS;
  362. }
  363. #pragma GCC diagnostic push
  364. #pragma GCC diagnostic ignored "-Wstack-protector"
  365. static test_return_t queue_restart_TEST(Context const* test, const int32_t inserted_jobs, uint32_t timeout)
  366. {
  367. SKIP_IF(HAVE_UUID_UUID_H != 1);
  368. server_startup_st &servers= test->_servers;
  369. std::string sql_file= libtest::create_tmpfile("sqlite");
  370. Sqlite sql_handle(sql_file);
  371. char sql_buffer[1024];
  372. snprintf(sql_buffer, sizeof(sql_buffer), "--libsqlite3-db=%.*s", int(sql_file.length()), sql_file.c_str());
  373. const char *argv[]= {
  374. "--queue-type=libsqlite3",
  375. sql_buffer,
  376. 0 };
  377. {
  378. in_port_t first_port= libtest::get_free_port();
  379. ASSERT_TRUE(server_startup(servers, "gearmand", first_port, argv));
  380. ASSERT_EQ(0, access(sql_file.c_str(), R_OK | W_OK ));
  381. {
  382. libgearman::Worker worker(first_port);
  383. ASSERT_EQ(gearman_worker_register(&worker, __func__, 0), GEARMAN_SUCCESS);
  384. }
  385. {
  386. libgearman::Client client(first_port);
  387. ASSERT_EQ(gearman_client_echo(&client, test_literal_param("This is my echo test")), GEARMAN_SUCCESS);
  388. gearman_job_handle_t job_handle;
  389. for (int32_t x= 0; x < inserted_jobs; ++x)
  390. {
  391. switch (random() % 3)
  392. {
  393. case 0:
  394. ASSERT_EQ(gearman_client_do_background(&client,
  395. __func__, // func
  396. NULL, // unique
  397. test_literal_param("foo"),
  398. job_handle), GEARMAN_SUCCESS);
  399. break;
  400. case 1:
  401. ASSERT_EQ(gearman_client_do_low_background(&client,
  402. __func__, // func
  403. NULL, // unique
  404. test_literal_param("fudge"),
  405. job_handle), GEARMAN_SUCCESS);
  406. break;
  407. default:
  408. case 2:
  409. ASSERT_EQ(gearman_client_do_high_background(&client,
  410. __func__, // func
  411. NULL, // unique
  412. test_literal_param("history"),
  413. job_handle), GEARMAN_SUCCESS);
  414. break;
  415. }
  416. }
  417. }
  418. servers.clear();
  419. }
  420. {
  421. if (sql_handle.vcount() != inserted_jobs)
  422. {
  423. ASSERT_EQ_(false, sql_handle.has_error(), "sqlite: %s", sql_handle.error_string().c_str());
  424. Out << "sql_handle.vprint_unique()";
  425. sql_handle.vprint_unique();
  426. }
  427. ASSERT_EQ(sql_handle.vcount(), inserted_jobs);
  428. }
  429. ASSERT_EQ(0, access(sql_file.c_str(), R_OK | W_OK ));
  430. {
  431. in_port_t first_port= libtest::get_free_port();
  432. ASSERT_TRUE(server_startup(servers, "gearmand", first_port, argv));
  433. if (timeout)
  434. {
  435. servers.last()->timeout(timeout);
  436. }
  437. {
  438. libgearman::Worker worker(first_port);
  439. Called called;
  440. gearman_function_t counter_function= gearman_function_create(called_worker);
  441. ASSERT_EQ(gearman_worker_define_function(&worker,
  442. test_literal_param(__func__),
  443. counter_function,
  444. 3000, &called), GEARMAN_SUCCESS);
  445. const int32_t max_timeout= 4;
  446. int32_t max_timeout_value= max_timeout;
  447. int32_t job_count= 0;
  448. gearman_return_t ret;
  449. do
  450. {
  451. ret= gearman_worker_work(&worker);
  452. if (gearman_success(ret))
  453. {
  454. job_count++;
  455. max_timeout_value= max_timeout;
  456. if (job_count == inserted_jobs)
  457. {
  458. break;
  459. }
  460. }
  461. else if (ret == GEARMAN_TIMEOUT)
  462. {
  463. Error << " hit timeout";
  464. if ((--max_timeout_value) < 0)
  465. {
  466. break;
  467. }
  468. }
  469. } while (ret == GEARMAN_TIMEOUT or ret == GEARMAN_SUCCESS);
  470. ASSERT_EQ(called.count(), inserted_jobs);
  471. }
  472. servers.clear();
  473. }
  474. {
  475. if (sql_handle.vcount() != 0)
  476. {
  477. ASSERT_EQ_(false, sql_handle.has_error(), "sqlite: %s", sql_handle.error_string().c_str());
  478. Out << "sql_handle.vprint_unique()";
  479. sql_handle.vprint_unique();
  480. }
  481. ASSERT_EQ(0, sql_handle.vcount());
  482. }
  483. return TEST_SUCCESS;
  484. }
  485. # pragma GCC diagnostic pop
  486. static test_return_t lp_1054377_TEST(void* object)
  487. {
  488. Context *test= (Context *)object;
  489. ASSERT_TRUE(test);
  490. return queue_restart_TEST(test, 8, 0);
  491. }
  492. static test_return_t lp_1054377x200_TEST(void* object)
  493. {
  494. test_skip(true, libtest::is_massive());
  495. Context *test= (Context *)object;
  496. ASSERT_TRUE(test);
  497. return queue_restart_TEST(test, 200, 200);
  498. }
  499. static test_return_t skip_SETUP(void*)
  500. {
  501. SKIP_IF(true);
  502. return TEST_SUCCESS;
  503. }
  504. static void *world_create(server_startup_st& servers, test_return_t&)
  505. {
  506. SKIP_IF(HAVE_UUID_UUID_H != 1);
  507. SKIP_IF(test_for_HAVE_LIBSQLITE3() == false);
  508. return new Context(servers);
  509. }
  510. static bool world_destroy(void *object)
  511. {
  512. Context *test= (Context *)object;
  513. delete test;
  514. return TEST_SUCCESS;
  515. }
  516. test_st gearmand_basic_option_tests[] ={
  517. {"--libsqlite3-db=var/tmp/schema --libsqlite3-table=custom_table", 0, gearmand_basic_option_test },
  518. {"--libsqlite3-db=var/tmp/schema", 0, gearmand_basic_option_without_table_test },
  519. {"--store-queue-on-shutdown", 0, gearmand_basic_option_shutdown_queue_TEST },
  520. {0, 0, 0}
  521. };
  522. test_st tests[] ={
  523. {"gearman_client_echo()", 0, client_echo_test },
  524. {"gearman_client_echo() fail", 0, client_echo_fail_test },
  525. {"gearman_worker_echo()", 0, worker_echo_test },
  526. {"clean", 0, queue_clean },
  527. {"add", 0, queue_add },
  528. {"worker", 0, queue_worker },
  529. {0, 0, 0}
  530. };
  531. test_st regressions[] ={
  532. {"lp:734663", 0, lp_734663 },
  533. {0, 0, 0}
  534. };
  535. test_st queue_restart_TESTS[] ={
  536. {"lp:1054377", 0, lp_1054377_TEST },
  537. {"lp:1054377 x 200", 0, lp_1054377x200_TEST },
  538. {"lp:1087654", 0, lp_1087654_TEST },
  539. {0, 0, 0}
  540. };
  541. collection_st collection[] ={
  542. {"gearmand options", 0, 0, gearmand_basic_option_tests},
  543. {"sqlite queue", collection_init, collection_cleanup, tests},
  544. {"queue regression", collection_init, collection_cleanup, regressions},
  545. {"queue restart", skip_SETUP, 0, queue_restart_TESTS},
  546. #if 0
  547. {"sqlite queue change table", collection_init, collection_cleanup, tests},
  548. #endif
  549. {0, 0, 0, 0}
  550. };
  551. void get_world(libtest::Framework *world)
  552. {
  553. world->collections(collection);
  554. world->create(world_create);
  555. world->destroy(world_destroy);
  556. }