test_datastore_api.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579
  1. /*
  2. This file is part of GNUnet.
  3. (C) 2004, 2005, 2006, 2007, 2009 Christian Grothoff (and other contributing authors)
  4. GNUnet is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published
  6. by the Free Software Foundation; either version 3, or (at your
  7. option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNUnet; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  15. Boston, MA 02111-1307, USA.
  16. */
  17. /*
  18. * @file datastore/test_datastore_api.c
  19. * @brief Test for the basic datastore API.
  20. * @author Christian Grothoff
  21. *
  22. * TODO:
  23. * - test reservation failure
  24. */
  25. #include "platform.h"
  26. #include "gnunet_util_lib.h"
  27. #include "gnunet_protocols.h"
  28. #include "gnunet_datastore_service.h"
  29. #define VERBOSE GNUNET_NO
  30. #define START_DATASTORE GNUNET_YES
  31. /**
  32. * How long until we give up on transmitting the message?
  33. */
  34. #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
  35. #define ITERATIONS 256
  36. static struct GNUNET_DATASTORE_Handle *datastore;
  37. static struct GNUNET_TIME_Absolute now;
  38. static int ok;
  39. /**
  40. * Name of plugin under test.
  41. */
  42. static const char *plugin_name;
  43. static size_t
  44. get_size (int i)
  45. {
  46. return 8 * i;
  47. }
  48. static const void *
  49. get_data (int i)
  50. {
  51. static char buf[60000];
  52. memset (buf, i, 8 * i);
  53. return buf;
  54. }
  55. static int
  56. get_type (int i)
  57. {
  58. return i + 1;
  59. }
  60. static int
  61. get_priority (int i)
  62. {
  63. return i + 1;
  64. }
  65. static int
  66. get_anonymity (int i)
  67. {
  68. return i;
  69. }
  70. static struct GNUNET_TIME_Absolute
  71. get_expiration (int i)
  72. {
  73. struct GNUNET_TIME_Absolute av;
  74. av.abs_value = now.abs_value + 20000000 - i * 1000;
  75. return av;
  76. }
  77. enum RunPhase
  78. {
  79. RP_DONE = 0,
  80. RP_PUT = 1,
  81. RP_GET = 2,
  82. RP_DEL = 3,
  83. RP_DO_DEL = 4,
  84. RP_DELVALIDATE = 5,
  85. RP_RESERVE = 6,
  86. RP_PUT_MULTIPLE = 7,
  87. RP_PUT_MULTIPLE_NEXT = 8,
  88. RP_GET_MULTIPLE = 9,
  89. RP_GET_MULTIPLE_NEXT = 10,
  90. RP_UPDATE = 11,
  91. RP_UPDATE_VALIDATE = 12,
  92. RP_ERROR
  93. };
  94. struct CpsRunContext
  95. {
  96. GNUNET_HashCode key;
  97. int i;
  98. int rid;
  99. const struct GNUNET_CONFIGURATION_Handle *cfg;
  100. void *data;
  101. size_t size;
  102. enum RunPhase phase;
  103. uint64_t uid;
  104. uint64_t offset;
  105. uint64_t first_uid;
  106. };
  107. static void
  108. run_continuation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
  109. static void
  110. check_success (void *cls, int success, const char *msg)
  111. {
  112. struct CpsRunContext *crc = cls;
  113. if (GNUNET_OK != success)
  114. {
  115. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  116. "Operation %d/%d not successfull: `%s'\n", crc->phase, crc->i,
  117. msg);
  118. crc->phase = RP_ERROR;
  119. }
  120. GNUNET_free_non_null (crc->data);
  121. crc->data = NULL;
  122. GNUNET_SCHEDULER_add_continuation (&run_continuation, crc,
  123. GNUNET_SCHEDULER_REASON_PREREQ_DONE);
  124. }
  125. static void
  126. get_reserved (void *cls, int success, const char *msg)
  127. {
  128. struct CpsRunContext *crc = cls;
  129. if (0 >= success)
  130. GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error obtaining reservation: `%s'\n",
  131. msg);
  132. GNUNET_assert (0 < success);
  133. crc->rid = success;
  134. GNUNET_SCHEDULER_add_continuation (&run_continuation, crc,
  135. GNUNET_SCHEDULER_REASON_PREREQ_DONE);
  136. }
  137. static void
  138. check_value (void *cls, const GNUNET_HashCode * key, size_t size,
  139. const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority,
  140. uint32_t anonymity, struct GNUNET_TIME_Absolute expiration,
  141. uint64_t uid)
  142. {
  143. struct CpsRunContext *crc = cls;
  144. int i;
  145. i = crc->i;
  146. #if 0
  147. fprintf (stderr, "Check value got `%s' of size %u, type %d, expire %llu\n",
  148. GNUNET_h2s (key), (unsigned int) size, type,
  149. (unsigned long long) expiration.abs_value);
  150. fprintf (stderr,
  151. "Check value iteration %d wants size %u, type %d, expire %llu\n", i,
  152. (unsigned int) get_size (i), get_type (i),
  153. (unsigned long long) get_expiration (i).abs_value);
  154. #endif
  155. GNUNET_assert (size == get_size (i));
  156. GNUNET_assert (0 == memcmp (data, get_data (i), size));
  157. GNUNET_assert (type == get_type (i));
  158. GNUNET_assert (priority == get_priority (i));
  159. GNUNET_assert (anonymity == get_anonymity (i));
  160. GNUNET_assert (expiration.abs_value == get_expiration (i).abs_value);
  161. crc->offset++;
  162. if (crc->i == 0)
  163. {
  164. crc->phase = RP_DEL;
  165. crc->i = ITERATIONS;
  166. }
  167. GNUNET_SCHEDULER_add_continuation (&run_continuation, crc,
  168. GNUNET_SCHEDULER_REASON_PREREQ_DONE);
  169. }
  170. static void
  171. delete_value (void *cls, const GNUNET_HashCode * key, size_t size,
  172. const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority,
  173. uint32_t anonymity, struct GNUNET_TIME_Absolute expiration,
  174. uint64_t uid)
  175. {
  176. struct CpsRunContext *crc = cls;
  177. GNUNET_assert (crc->data == NULL);
  178. GNUNET_assert (NULL != key);
  179. crc->size = size;
  180. crc->key = *key;
  181. crc->data = GNUNET_malloc (size);
  182. memcpy (crc->data, data, size);
  183. crc->phase = RP_DO_DEL;
  184. GNUNET_SCHEDULER_add_continuation (&run_continuation, crc,
  185. GNUNET_SCHEDULER_REASON_PREREQ_DONE);
  186. }
  187. static void
  188. check_nothing (void *cls, const GNUNET_HashCode * key, size_t size,
  189. const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority,
  190. uint32_t anonymity, struct GNUNET_TIME_Absolute expiration,
  191. uint64_t uid)
  192. {
  193. struct CpsRunContext *crc = cls;
  194. GNUNET_assert (key == NULL);
  195. if (crc->i == 0)
  196. crc->phase = RP_RESERVE;
  197. GNUNET_SCHEDULER_add_continuation (&run_continuation, crc,
  198. GNUNET_SCHEDULER_REASON_PREREQ_DONE);
  199. }
  200. static void
  201. check_multiple (void *cls, const GNUNET_HashCode * key, size_t size,
  202. const void *data, enum GNUNET_BLOCK_Type type,
  203. uint32_t priority, uint32_t anonymity,
  204. struct GNUNET_TIME_Absolute expiration, uint64_t uid)
  205. {
  206. struct CpsRunContext *crc = cls;
  207. GNUNET_assert (key != NULL);
  208. switch (crc->phase)
  209. {
  210. case RP_GET_MULTIPLE:
  211. crc->phase = RP_GET_MULTIPLE_NEXT;
  212. crc->first_uid = uid;
  213. crc->offset++;
  214. break;
  215. case RP_GET_MULTIPLE_NEXT:
  216. GNUNET_assert (uid != crc->first_uid);
  217. crc->phase = RP_UPDATE;
  218. break;
  219. default:
  220. GNUNET_break (0);
  221. crc->phase = RP_ERROR;
  222. break;
  223. }
  224. if (priority == get_priority (42))
  225. crc->uid = uid;
  226. GNUNET_SCHEDULER_add_continuation (&run_continuation, crc,
  227. GNUNET_SCHEDULER_REASON_PREREQ_DONE);
  228. }
  229. static void
  230. check_update (void *cls, const GNUNET_HashCode * key, size_t size,
  231. const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority,
  232. uint32_t anonymity, struct GNUNET_TIME_Absolute expiration,
  233. uint64_t uid)
  234. {
  235. struct CpsRunContext *crc = cls;
  236. GNUNET_assert (key != NULL);
  237. if ((anonymity == get_anonymity (42)) && (size == get_size (42)) &&
  238. (priority == get_priority (42) + 100))
  239. crc->phase = RP_DONE;
  240. else
  241. {
  242. GNUNET_assert (size == get_size (43));
  243. crc->offset++;
  244. }
  245. GNUNET_SCHEDULER_add_continuation (&run_continuation, crc,
  246. GNUNET_SCHEDULER_REASON_PREREQ_DONE);
  247. }
  248. static void
  249. run_continuation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  250. {
  251. struct CpsRunContext *crc = cls;
  252. ok = (int) crc->phase;
  253. #if VERBOSE
  254. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test in phase %u\n", crc->phase);
  255. #endif
  256. switch (crc->phase)
  257. {
  258. case RP_PUT:
  259. #if VERBOSE
  260. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "PUT",
  261. crc->i);
  262. #endif
  263. GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
  264. GNUNET_DATASTORE_put (datastore, 0, &crc->key, get_size (crc->i),
  265. get_data (crc->i), get_type (crc->i),
  266. get_priority (crc->i), get_anonymity (crc->i), 0,
  267. get_expiration (crc->i), 1, 1, TIMEOUT,
  268. &check_success, crc);
  269. crc->i++;
  270. if (crc->i == ITERATIONS)
  271. crc->phase = RP_GET;
  272. break;
  273. case RP_GET:
  274. crc->i--;
  275. #if VERBOSE
  276. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "GET",
  277. crc->i);
  278. #endif
  279. GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
  280. GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key,
  281. get_type (crc->i), 1, 1, TIMEOUT, &check_value,
  282. crc);
  283. break;
  284. case RP_DEL:
  285. crc->i--;
  286. #if VERBOSE
  287. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "DEL",
  288. crc->i);
  289. #endif
  290. crc->data = NULL;
  291. GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
  292. GNUNET_assert (NULL !=
  293. GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key,
  294. get_type (crc->i), 1, 1, TIMEOUT,
  295. &delete_value, crc));
  296. break;
  297. case RP_DO_DEL:
  298. #if VERBOSE
  299. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "DO_DEL",
  300. crc->i);
  301. #endif
  302. if (crc->i == 0)
  303. {
  304. crc->i = ITERATIONS;
  305. crc->phase = RP_DELVALIDATE;
  306. }
  307. else
  308. {
  309. crc->phase = RP_DEL;
  310. }
  311. GNUNET_assert (NULL !=
  312. GNUNET_DATASTORE_remove (datastore, &crc->key, crc->size,
  313. crc->data, 1, 1, TIMEOUT,
  314. &check_success, crc));
  315. break;
  316. case RP_DELVALIDATE:
  317. crc->i--;
  318. #if VERBOSE
  319. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n",
  320. "DEL-VALIDATE", crc->i);
  321. #endif
  322. GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
  323. GNUNET_assert (NULL !=
  324. GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key,
  325. get_type (crc->i), 1, 1, TIMEOUT,
  326. &check_nothing, crc));
  327. break;
  328. case RP_RESERVE:
  329. crc->phase = RP_PUT_MULTIPLE;
  330. GNUNET_DATASTORE_reserve (datastore, 128 * 1024, 2, 1, 1, TIMEOUT,
  331. &get_reserved, crc);
  332. break;
  333. case RP_PUT_MULTIPLE:
  334. crc->phase = RP_PUT_MULTIPLE_NEXT;
  335. GNUNET_DATASTORE_put (datastore, crc->rid, &crc->key, get_size (42),
  336. get_data (42), get_type (42), get_priority (42),
  337. get_anonymity (42), 0, get_expiration (42), 1, 1,
  338. TIMEOUT, &check_success, crc);
  339. break;
  340. case RP_PUT_MULTIPLE_NEXT:
  341. crc->phase = RP_GET_MULTIPLE;
  342. GNUNET_DATASTORE_put (datastore, crc->rid, &crc->key, get_size (43),
  343. get_data (43), get_type (42), get_priority (43),
  344. get_anonymity (43), 0, get_expiration (43), 1, 1,
  345. TIMEOUT, &check_success, crc);
  346. break;
  347. case RP_GET_MULTIPLE:
  348. GNUNET_assert (NULL !=
  349. GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key,
  350. get_type (42), 1, 1, TIMEOUT,
  351. &check_multiple, crc));
  352. break;
  353. case RP_GET_MULTIPLE_NEXT:
  354. GNUNET_assert (NULL !=
  355. GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key,
  356. get_type (42), 1, 1, TIMEOUT,
  357. &check_multiple, crc));
  358. break;
  359. case RP_UPDATE:
  360. GNUNET_assert (crc->uid > 0);
  361. crc->phase = RP_UPDATE_VALIDATE;
  362. GNUNET_DATASTORE_update (datastore, crc->uid, 100, get_expiration (42), 1,
  363. 1, TIMEOUT, &check_success, crc);
  364. break;
  365. case RP_UPDATE_VALIDATE:
  366. GNUNET_assert (NULL !=
  367. GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key,
  368. get_type (42), 1, 1, TIMEOUT,
  369. &check_update, crc));
  370. break;
  371. case RP_DONE:
  372. #if VERBOSE
  373. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished, disconnecting\n");
  374. #endif
  375. GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES);
  376. GNUNET_free (crc);
  377. ok = 0;
  378. break;
  379. case RP_ERROR:
  380. GNUNET_DATASTORE_disconnect (datastore, GNUNET_YES);
  381. GNUNET_free (crc);
  382. ok = 43;
  383. break;
  384. }
  385. }
  386. static void
  387. run_tests (void *cls, int32_t success, const char *msg)
  388. {
  389. struct CpsRunContext *crc = cls;
  390. switch (success)
  391. {
  392. case GNUNET_YES:
  393. GNUNET_SCHEDULER_add_continuation (&run_continuation, crc,
  394. GNUNET_SCHEDULER_REASON_PREREQ_DONE);
  395. return;
  396. case GNUNET_NO:
  397. fprintf (stderr, "Test 'put' operation failed, key already exists (!?)\n");
  398. GNUNET_free (crc);
  399. return;
  400. case GNUNET_SYSERR:
  401. fprintf (stderr,
  402. "Test 'put' operation failed with error `%s' database likely not setup, skipping test.\n",
  403. msg);
  404. GNUNET_free (crc);
  405. return;
  406. default:
  407. GNUNET_assert (0);
  408. }
  409. }
  410. static void
  411. run (void *cls, char *const *args, const char *cfgfile,
  412. const struct GNUNET_CONFIGURATION_Handle *cfg)
  413. {
  414. struct CpsRunContext *crc;
  415. static GNUNET_HashCode zkey;
  416. crc = GNUNET_malloc (sizeof (struct CpsRunContext));
  417. crc->cfg = cfg;
  418. crc->phase = RP_PUT;
  419. now = GNUNET_TIME_absolute_get ();
  420. datastore = GNUNET_DATASTORE_connect (cfg);
  421. if (NULL ==
  422. GNUNET_DATASTORE_put (datastore, 0, &zkey, 4, "TEST",
  423. GNUNET_BLOCK_TYPE_TEST, 0, 0, 0,
  424. GNUNET_TIME_relative_to_absolute
  425. (GNUNET_TIME_UNIT_SECONDS), 0, 1,
  426. GNUNET_TIME_UNIT_MINUTES, &run_tests, crc))
  427. {
  428. fprintf (stderr, "Test 'put' operation failed.\n");
  429. ok = 1;
  430. GNUNET_free (crc);
  431. }
  432. }
  433. static int
  434. check ()
  435. {
  436. char cfg_name[128];
  437. #if START_DATASTORE
  438. struct GNUNET_OS_Process *proc;
  439. #endif
  440. char *const argv[] = {
  441. "test-datastore-api",
  442. "-c",
  443. cfg_name,
  444. #if VERBOSE
  445. "-L", "DEBUG",
  446. #endif
  447. NULL
  448. };
  449. struct GNUNET_GETOPT_CommandLineOption options[] = {
  450. GNUNET_GETOPT_OPTION_END
  451. };
  452. GNUNET_snprintf (cfg_name, sizeof (cfg_name),
  453. "test_datastore_api_data_%s.conf", plugin_name);
  454. #if START_DATASTORE
  455. proc =
  456. GNUNET_OS_start_process (NULL, NULL, "gnunet-service-arm",
  457. "gnunet-service-arm",
  458. #if VERBOSE
  459. "-L", "DEBUG",
  460. #endif
  461. "-c", cfg_name, NULL);
  462. #endif
  463. GNUNET_assert (NULL != proc);
  464. GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv,
  465. "test-datastore-api", "nohelp", options, &run, NULL);
  466. #if START_DATASTORE
  467. sleep (1); /* give datastore chance to receive 'DROP' request */
  468. if (0 != GNUNET_OS_process_kill (proc, SIGTERM))
  469. {
  470. GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
  471. ok = 1;
  472. }
  473. GNUNET_OS_process_wait (proc);
  474. GNUNET_OS_process_close (proc);
  475. proc = NULL;
  476. #endif
  477. if (ok != 0)
  478. fprintf (stderr, "Missed some testcases: %u\n", ok);
  479. return ok;
  480. }
  481. int
  482. main (int argc, char *argv[])
  483. {
  484. int ret;
  485. char *pos;
  486. char dir_name[128];
  487. sleep (1);
  488. /* determine name of plugin to use */
  489. plugin_name = argv[0];
  490. while (NULL != (pos = strstr (plugin_name, "_")))
  491. plugin_name = pos + 1;
  492. if (NULL != (pos = strstr (plugin_name, ".")))
  493. pos[0] = 0;
  494. else
  495. pos = (char *) plugin_name;
  496. GNUNET_snprintf (dir_name, sizeof (dir_name), "/tmp/test-gnunet-datastore-%s",
  497. plugin_name);
  498. GNUNET_DISK_directory_remove (dir_name);
  499. GNUNET_log_setup ("test-datastore-api",
  500. #if VERBOSE
  501. "DEBUG",
  502. #else
  503. "WARNING",
  504. #endif
  505. NULL);
  506. ret = check ();
  507. if (pos != plugin_name)
  508. pos[0] = '.';
  509. GNUNET_DISK_directory_remove (dir_name);
  510. return ret;
  511. }
  512. /* end of test_datastore_api.c */