aboutsummaryrefslogtreecommitdiff
path: root/src/lib/pq/test_pq.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/pq/test_pq.c')
-rw-r--r--src/lib/pq/test_pq.c630
1 files changed, 630 insertions, 0 deletions
diff --git a/src/lib/pq/test_pq.c b/src/lib/pq/test_pq.c
new file mode 100644
index 000000000..813c4a019
--- /dev/null
+++ b/src/lib/pq/test_pq.c
@@ -0,0 +1,630 @@
1/*
2 This file is part of GNUnet
3 (C) 2015, 2016, 2019, 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file pq/test_pq.c
22 * @brief Tests for Postgres convenience API
23 * @author Christian Grothoff <christian@grothoff.org>
24 */
25#include "platform.h"
26#include "gnunet_common.h"
27#include "gnunet_pq_lib.h"
28#include "gnunet_time_lib.h"
29#include "pq.h"
30
31/**
32 * Database handle.
33 */
34static struct GNUNET_PQ_Context *db;
35
36/**
37 * Global return value, 0 on success.
38 */
39static int ret;
40
41/**
42 * An event handler.
43 */
44static struct GNUNET_DB_EventHandler *eh;
45
46/**
47 * Timeout task.
48 */
49static struct GNUNET_SCHEDULER_Task *tt;
50
51
52/**
53 * Setup prepared statements.
54 *
55 * @param db database handle to initialize
56 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
57 */
58static int
59postgres_prepare (struct GNUNET_PQ_Context *db)
60{
61 struct GNUNET_PQ_PreparedStatement ps[] = {
62 GNUNET_PQ_make_prepare ("test_insert",
63 "INSERT INTO test_pq ("
64 " pub"
65 ",sig"
66 ",abs_time"
67 ",forever"
68 ",hash"
69 ",vsize"
70 ",u16"
71 ",u32"
72 ",u64"
73 ",unn"
74 ",arr_bool"
75 ",arr_int2"
76 ",arr_int4"
77 ",arr_int8"
78 ",arr_bytea"
79 ",arr_text"
80 ",arr_abs_time"
81 ",arr_rel_time"
82 ",arr_timestamp"
83 ") VALUES "
84 "($1, $2, $3, $4, $5, $6,"
85 "$7, $8, $9, $10,"
86 "$11, $12, $13, $14, $15, $16,"
87 "$17, $18, $19);"),
88 GNUNET_PQ_make_prepare ("test_select",
89 "SELECT"
90 " pub"
91 ",sig"
92 ",abs_time"
93 ",forever"
94 ",hash"
95 ",vsize"
96 ",u16"
97 ",u32"
98 ",u64"
99 ",unn"
100 ",arr_bool"
101 ",arr_int2"
102 ",arr_int4"
103 ",arr_int8"
104 ",arr_bytea"
105 ",arr_text"
106 ",arr_abs_time"
107 ",arr_rel_time"
108 ",arr_timestamp"
109 " FROM test_pq"
110 " ORDER BY abs_time DESC "
111 " LIMIT 1;"),
112 GNUNET_PQ_PREPARED_STATEMENT_END
113 };
114
115 return GNUNET_PQ_prepare_statements (db,
116 ps);
117}
118
119
120/**
121 * Run actual test queries.
122 *
123 * @param db database handle
124 * @return 0 on success
125 */
126static int
127run_queries (struct GNUNET_PQ_Context *db)
128{
129 struct GNUNET_CRYPTO_RsaPublicKey *pub;
130 struct GNUNET_CRYPTO_RsaPublicKey *pub2 = NULL;
131 struct GNUNET_CRYPTO_RsaSignature *sig;
132 struct GNUNET_CRYPTO_RsaSignature *sig2 = NULL;
133 struct GNUNET_TIME_Absolute abs_time = GNUNET_TIME_absolute_get ();
134 struct GNUNET_TIME_Absolute abs_time2;
135 struct GNUNET_TIME_Absolute forever = GNUNET_TIME_UNIT_FOREVER_ABS;
136 struct GNUNET_TIME_Absolute forever2;
137 struct GNUNET_HashCode hc;
138 struct GNUNET_HashCode hc2;
139 PGresult *result;
140 int ret;
141 struct GNUNET_CRYPTO_RsaPrivateKey *priv;
142 const char msg[] = "hello";
143 void *msg2;
144 struct GNUNET_HashCode hmsg;
145 size_t msg2_len;
146 uint16_t u16;
147 uint16_t u162;
148 uint32_t u32;
149 uint32_t u322;
150 uint64_t u64;
151 uint64_t u642;
152 uint64_t uzzz = 42;
153 struct GNUNET_HashCode ahc[3] = {};
154 bool ab[5] = {true, false, false, true, false};
155 uint16_t ai2[3] = {42, 0x0001, 0xFFFF};
156 uint32_t ai4[3] = {42, 0x00010000, 0xFFFFFFFF};
157 uint64_t ai8[3] = {42, 0x0001000000000000, 0xFFFFFFFFFFFFFFFF};
158 const char *as[] = {"foo", "bar", "buzz"};
159 const struct GNUNET_TIME_Absolute ata[2] = {GNUNET_TIME_absolute_get (),
160 GNUNET_TIME_absolute_get ()};
161 const struct GNUNET_TIME_Relative atr[2] = {GNUNET_TIME_relative_get_hour_ (),
162 GNUNET_TIME_relative_get_minute_ ()};
163 const struct GNUNET_TIME_Timestamp ats[2] = {GNUNET_TIME_timestamp_get (),
164 GNUNET_TIME_timestamp_get ()};
165
166
167 priv = GNUNET_CRYPTO_rsa_private_key_create (1024);
168 pub = GNUNET_CRYPTO_rsa_private_key_get_public (priv);
169 memset (&hmsg, 42, sizeof(hmsg));
170 sig = GNUNET_CRYPTO_rsa_sign_fdh (priv,
171 &hmsg,
172 sizeof (hmsg));
173 u16 = 16;
174 u32 = 32;
175 u64 = 64;
176 for (int i = 0; i < 3; i++)
177 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
178 &ahc[i],
179 sizeof(ahc[i]));
180
181 /* FIXME: test GNUNET_PQ_result_spec_variable_size */
182 {
183 struct GNUNET_PQ_QueryParam params_insert[] = {
184 GNUNET_PQ_query_param_rsa_public_key (pub),
185 GNUNET_PQ_query_param_rsa_signature (sig),
186 GNUNET_PQ_query_param_absolute_time (&abs_time),
187 GNUNET_PQ_query_param_absolute_time (&forever),
188 GNUNET_PQ_query_param_auto_from_type (&hc),
189 GNUNET_PQ_query_param_string (msg),
190 GNUNET_PQ_query_param_uint16 (&u16),
191 GNUNET_PQ_query_param_uint32 (&u32),
192 GNUNET_PQ_query_param_uint64 (&u64),
193 GNUNET_PQ_query_param_null (),
194 GNUNET_PQ_query_param_array_bool (5, ab, db),
195 GNUNET_PQ_query_param_array_uint16 (3, ai2, db),
196 GNUNET_PQ_query_param_array_uint32 (3, ai4, db),
197 GNUNET_PQ_query_param_array_uint64 (3, ai8, db),
198 GNUNET_PQ_query_param_array_bytes_same_size (3,
199 ahc,
200 sizeof(ahc[0]),
201 db),
202 GNUNET_PQ_query_param_array_ptrs_string (3, as, db),
203 GNUNET_PQ_query_param_array_abs_time (2, ata, db),
204 GNUNET_PQ_query_param_array_rel_time (2, atr, db),
205 GNUNET_PQ_query_param_array_timestamp (2, ats, db),
206 GNUNET_PQ_query_param_end
207 };
208 struct GNUNET_PQ_QueryParam params_select[] = {
209 GNUNET_PQ_query_param_end
210 };
211 bool got_null = false;
212 size_t num_bool;
213 bool *arr_bools;
214 size_t num_u16;
215 uint16_t *arr_u16;
216 size_t num_u32;
217 uint32_t *arr_u32;
218 size_t num_u64;
219 uint64_t *arr_u64;
220 size_t num_abs;
221 struct GNUNET_TIME_Absolute *arr_abs;
222 size_t num_rel;
223 struct GNUNET_TIME_Relative *arr_rel;
224 size_t num_tstmp;
225 struct GNUNET_TIME_Timestamp *arr_tstmp;
226 size_t num_str;
227 char *arr_str;
228 size_t num_hash;
229 struct GNUNET_HashCode *arr_hash;
230 size_t num_buf;
231 void *arr_buf;
232 size_t *sz_buf;
233 struct GNUNET_PQ_ResultSpec results_select[] = {
234 GNUNET_PQ_result_spec_rsa_public_key ("pub", &pub2),
235 GNUNET_PQ_result_spec_rsa_signature ("sig", &sig2),
236 GNUNET_PQ_result_spec_absolute_time ("abs_time", &abs_time2),
237 GNUNET_PQ_result_spec_absolute_time ("forever", &forever2),
238 GNUNET_PQ_result_spec_auto_from_type ("hash", &hc2),
239 GNUNET_PQ_result_spec_variable_size ("vsize", &msg2, &msg2_len),
240 GNUNET_PQ_result_spec_uint16 ("u16", &u162),
241 GNUNET_PQ_result_spec_uint32 ("u32", &u322),
242 GNUNET_PQ_result_spec_uint64 ("u64", &u642),
243 GNUNET_PQ_result_spec_allow_null (
244 GNUNET_PQ_result_spec_uint64 ("unn", &uzzz),
245 &got_null),
246 GNUNET_PQ_result_spec_array_bool (db,
247 "arr_bool",
248 &num_bool,
249 &arr_bools),
250 GNUNET_PQ_result_spec_array_uint16 (db,
251 "arr_int2",
252 &num_u16,
253 &arr_u16),
254 GNUNET_PQ_result_spec_array_uint32 (db,
255 "arr_int4",
256 &num_u32,
257 &arr_u32),
258 GNUNET_PQ_result_spec_array_uint64 (db,
259 "arr_int8",
260 &num_u64,
261 &arr_u64),
262 GNUNET_PQ_result_spec_array_abs_time (db,
263 "arr_abs_time",
264 &num_abs,
265 &arr_abs),
266 GNUNET_PQ_result_spec_array_rel_time (db,
267 "arr_rel_time",
268 &num_rel,
269 &arr_rel),
270 GNUNET_PQ_result_spec_array_timestamp (db,
271 "arr_timestamp",
272 &num_tstmp,
273 &arr_tstmp),
274 GNUNET_PQ_result_spec_auto_array_from_type (db,
275 "arr_bytea",
276 &num_hash,
277 arr_hash),
278 GNUNET_PQ_result_spec_array_variable_size (db,
279 "arr_bytea",
280 &num_buf,
281 &sz_buf,
282 &arr_buf),
283 GNUNET_PQ_result_spec_array_string (db,
284 "arr_text",
285 &num_str,
286 &arr_str),
287 GNUNET_PQ_result_spec_end
288 };
289
290 result = GNUNET_PQ_exec_prepared (db,
291 "test_insert",
292 params_insert);
293 if (PGRES_COMMAND_OK != PQresultStatus (result))
294 {
295 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
296 "Database failure: %s\n",
297 PQresultErrorMessage (result));
298 PQclear (result);
299 GNUNET_CRYPTO_rsa_signature_free (sig);
300 GNUNET_CRYPTO_rsa_private_key_free (priv);
301 GNUNET_CRYPTO_rsa_public_key_free (pub);
302 return 1;
303 }
304
305 PQclear (result);
306 result = GNUNET_PQ_exec_prepared (db,
307 "test_select",
308 params_select);
309 if (1 !=
310 PQntuples (result))
311 {
312 GNUNET_break (0);
313 PQclear (result);
314 GNUNET_CRYPTO_rsa_signature_free (sig);
315 GNUNET_CRYPTO_rsa_private_key_free (priv);
316 GNUNET_CRYPTO_rsa_public_key_free (pub);
317 return 1;
318 }
319 ret = GNUNET_PQ_extract_result (result,
320 results_select,
321 0);
322 GNUNET_break (GNUNET_YES == ret);
323 GNUNET_break (abs_time.abs_value_us == abs_time2.abs_value_us);
324 GNUNET_break (forever.abs_value_us == forever2.abs_value_us);
325 GNUNET_break (0 ==
326 GNUNET_memcmp (&hc,
327 &hc2));
328 GNUNET_break (0 ==
329 GNUNET_CRYPTO_rsa_signature_cmp (sig,
330 sig2));
331 GNUNET_break (0 ==
332 GNUNET_CRYPTO_rsa_public_key_cmp (pub,
333 pub2));
334 GNUNET_break (strlen (msg) == msg2_len);
335 GNUNET_break (0 ==
336 strncmp (msg,
337 msg2,
338 msg2_len));
339 GNUNET_break (16 == u162);
340 GNUNET_break (32 == u322);
341 GNUNET_break (64 == u642);
342 GNUNET_break (42 == uzzz);
343 GNUNET_break (got_null);
344
345 /* Check arrays */
346 GNUNET_break (num_bool == 5);
347 for (size_t i = 0; i < num_bool; i++)
348 GNUNET_break (arr_bools[i] == ab[i]);
349
350 GNUNET_break (num_u16 == 3);
351 for (size_t i = 0; i < num_u16; i++)
352 GNUNET_break (arr_u16[i] == ai2[i]);
353
354 GNUNET_break (num_u32 == 3);
355 for (size_t i = 0; i < num_u32; i++)
356 GNUNET_break (arr_u32[i] == ai4[i]);
357
358 GNUNET_break (num_u64 == 3);
359 for (size_t i = 0; i < num_u64; i++)
360 GNUNET_break (arr_u64[i] == ai8[i]);
361
362 GNUNET_break (num_abs == 2);
363 for (size_t i = 0; i < num_abs; i++)
364 GNUNET_break (arr_abs[i].abs_value_us == ata[i].abs_value_us);
365
366 GNUNET_break (num_rel == 2);
367 for (size_t i = 0; i < num_rel; i++)
368 GNUNET_break (arr_rel[i].rel_value_us == atr[i].rel_value_us);
369
370 GNUNET_break (num_tstmp == 2);
371 for (size_t i = 0; i < num_tstmp; i++)
372 GNUNET_break (arr_tstmp[i].abs_time.abs_value_us ==
373 ats[i].abs_time.abs_value_us);
374
375 GNUNET_break (num_str == 3);
376 GNUNET_break (0 == strcmp (arr_str, as[0]));
377 GNUNET_break (0 == strcmp (arr_str + 4, as[1]));
378 GNUNET_break (0 == strcmp (arr_str + 8, as[2]));
379
380 GNUNET_break (num_hash == 3);
381 for (size_t i = 0; i < num_hash; i++)
382 GNUNET_break (0 == GNUNET_memcmp (&arr_hash[i], &ahc[i]));
383
384 GNUNET_break (num_buf == 3);
385 for (size_t i = 0; i < num_buf; i++)
386 {
387 GNUNET_break (0 == memcmp (((char *) arr_buf) + i * sizeof(ahc[i]),
388 &ahc[i],
389 sizeof(ahc[i])));
390 }
391
392 GNUNET_PQ_cleanup_result (results_select);
393 PQclear (result);
394
395 GNUNET_PQ_cleanup_query_params_closures (params_insert);
396 }
397
398 GNUNET_CRYPTO_rsa_signature_free (sig);
399 GNUNET_CRYPTO_rsa_private_key_free (priv);
400 GNUNET_CRYPTO_rsa_public_key_free (pub);
401 if (GNUNET_OK != ret)
402 return 1;
403
404 return 0;
405}
406
407
408/**
409 * Task called on shutdown.
410 *
411 * @param cls NULL
412 */
413static void
414event_end (void *cls)
415{
416 GNUNET_PQ_event_listen_cancel (eh);
417 eh = NULL;
418 if (NULL != tt)
419 {
420 GNUNET_SCHEDULER_cancel (tt);
421 tt = NULL;
422 }
423}
424
425
426/**
427 * Task called on timeout. Should not happen, means
428 * we did not get the expected event.
429 *
430 * @param cls NULL
431 */
432static void
433timeout_cb (void *cls)
434{
435 ret = 2;
436 GNUNET_break (0);
437 tt = NULL;
438 GNUNET_SCHEDULER_shutdown ();
439}
440
441
442/**
443 * Task called on expected event
444 *
445 * @param cls NULL
446 */
447static void
448event_sched_cb (void *cls,
449 const void *extra,
450 size_t extra_size)
451{
452 GNUNET_assert (5 == extra_size);
453 GNUNET_assert (0 ==
454 memcmp ("hello",
455 extra,
456 5));
457 GNUNET_SCHEDULER_shutdown ();
458}
459
460
461/**
462 * Run tests that need a scheduler.
463 *
464 * @param cls NULL
465 */
466static void
467sched_tests (void *cls)
468{
469 struct GNUNET_DB_EventHeaderP es = {
470 .size = htons (sizeof (es)),
471 .type = htons (42)
472 };
473
474
475 tt = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
476 &timeout_cb,
477 NULL);
478 eh = GNUNET_PQ_event_listen (db,
479 &es,
480 GNUNET_TIME_UNIT_FOREVER_REL,
481 &event_sched_cb,
482 NULL);
483 GNUNET_PQ_reconnect (db);
484 GNUNET_SCHEDULER_add_shutdown (&event_end,
485 NULL);
486 GNUNET_PQ_event_notify (db,
487 &es,
488 "hello",
489 5);
490}
491
492
493int
494main (int argc,
495 const char *const argv[])
496{
497 struct GNUNET_PQ_ExecuteStatement es[] = {
498 GNUNET_PQ_make_execute ("CREATE TEMPORARY TABLE IF NOT EXISTS test_pq ("
499 " pub BYTEA NOT NULL"
500 ",sig BYTEA NOT NULL"
501 ",abs_time INT8 NOT NULL"
502 ",forever INT8 NOT NULL"
503 ",hash BYTEA NOT NULL CHECK(LENGTH(hash)=64)"
504 ",vsize VARCHAR NOT NULL"
505 ",u16 INT2 NOT NULL"
506 ",u32 INT4 NOT NULL"
507 ",u64 INT8 NOT NULL"
508 ",unn INT8"
509 ",arr_bool BOOL[]"
510 ",arr_int2 INT2[]"
511 ",arr_int4 INT4[]"
512 ",arr_int8 INT8[]"
513 ",arr_bytea BYTEA[]"
514 ",arr_text TEXT[]"
515 ",arr_abs_time INT8[]"
516 ",arr_rel_time INT8[]"
517 ",arr_timestamp INT8[]"
518 ")"),
519 GNUNET_PQ_EXECUTE_STATEMENT_END
520 };
521
522 GNUNET_log_setup ("test-pq",
523 "INFO",
524 NULL);
525 db = GNUNET_PQ_connect ("postgres:///gnunetcheck",
526 NULL,
527 es,
528 NULL);
529 if (NULL == db)
530 {
531 fprintf (stderr,
532 "Cannot run test, database connection failed\n");
533 return 77;
534 }
535 if (CONNECTION_OK != PQstatus (db->conn))
536 {
537 fprintf (stderr,
538 "Cannot run test, database connection failed: %s\n",
539 PQerrorMessage (db->conn));
540 GNUNET_break (0);
541 GNUNET_PQ_disconnect (db);
542 return 77; /* signal test was skipped */
543 }
544 if (GNUNET_OK !=
545 postgres_prepare (db))
546 {
547 GNUNET_break (0);
548 GNUNET_PQ_disconnect (db);
549 return 1;
550 }
551 ret = run_queries (db);
552 if (0 != ret)
553 {
554 GNUNET_break (0);
555 GNUNET_PQ_disconnect (db);
556 return ret;
557 }
558
559 /* ensure oid lookup works */
560 {
561 enum GNUNET_GenericReturnValue ret;
562 Oid oid;
563
564 ret = GNUNET_PQ_get_oid_by_name (db, "int8", &oid);
565
566 if (GNUNET_OK != ret)
567 {
568 fprintf (stderr,
569 "Cannot lookup oid for int8: %s\n",
570 PQerrorMessage (db->conn));
571 GNUNET_break (0);
572 GNUNET_PQ_disconnect (db);
573 return 77; /* signal test was skipped */
574 }
575
576 PQexec (db->conn, "CREATE TYPE foo AS (foo int, bar int);");
577
578 ret = GNUNET_PQ_get_oid_by_name (db, "foo", &oid);
579 if (GNUNET_OK != ret)
580 {
581 fprintf (stderr,
582 "Cannot lookup oid for foo: %s\n",
583 PQerrorMessage (db->conn));
584 GNUNET_break (0);
585 GNUNET_PQ_disconnect (db);
586 return 77; /* signal test was skipped */
587 }
588
589 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
590 "got oid %d for type foo\n", oid);
591 }
592
593 GNUNET_SCHEDULER_run (&sched_tests,
594 NULL);
595 if (0 != ret)
596 {
597 GNUNET_break (0);
598 GNUNET_PQ_disconnect (db);
599 return ret;
600 }
601#if TEST_RESTART
602 fprintf (stderr, "Please restart Postgres database now!\n");
603 sleep (60);
604 ret |= run_queries (db);
605 fprintf (stderr, "Result: %d (expect: 1 -- if you restarted the DB)\n", ret);
606 ret |= run_queries (db);
607 fprintf (stderr, "Result: %d (expect: 0)\n", ret);
608#endif
609 {
610 struct GNUNET_PQ_ExecuteStatement es[] = {
611 GNUNET_PQ_make_execute ("DROP TABLE test_pq"),
612 GNUNET_PQ_EXECUTE_STATEMENT_END
613 };
614
615 if (GNUNET_OK !=
616 GNUNET_PQ_exec_statements (db,
617 es))
618 {
619 fprintf (stderr,
620 "Failed to drop table\n");
621 GNUNET_PQ_disconnect (db);
622 return 1;
623 }
624 }
625 GNUNET_PQ_disconnect (db);
626 return ret;
627}
628
629
630/* end of test_pq.c */