More API function tests...
[oweals/gnunet.git] / src / pq / test_pq.c
1 /*
2   This file is part of GNUnet
3   (C) 2015, 2016 GNUnet e.V.
4
5   GNUnet is free software; you can redistribute it and/or modify it under the
6   terms of the GNU General Public License as published by the Free Software
7   Foundation; either version 3, or (at your option) any later version.
8
9   GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY
10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
12
13   You should have received a copy of the GNU General Public License along with
14   GNUnet; see the file COPYING.  If not, If not, see <http://www.gnu.org/licenses/>
15 */
16 /**
17  * @file pq/test_pq.c
18  * @brief Tests for Postgres convenience API
19  * @author Christian Grothoff <christian@grothoff.org>
20  */
21 #include "platform.h"
22 #include "gnunet_util_lib.h"
23 #include "gnunet_pq_lib.h"
24
25
26 /**
27  * Setup prepared statements.
28  *
29  * @param db_conn connection handle to initialize
30  * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
31  */
32 static int
33 postgres_prepare (PGconn *db_conn)
34 {
35   PGresult *result;
36
37 #define PREPARE(name, sql, ...)                                 \
38   do {                                                          \
39     result = PQprepare (db_conn, name, sql, __VA_ARGS__);       \
40     if (PGRES_COMMAND_OK != PQresultStatus (result))            \
41     {                                                           \
42       GNUNET_break (0);                                         \
43       PQclear (result); result = NULL;                          \
44       return GNUNET_SYSERR;                                     \
45     }                                                           \
46     PQclear (result); result = NULL;                            \
47   } while (0);
48
49   PREPARE ("test_insert",
50            "INSERT INTO test_pq ("
51            " pub"
52            ",sig"
53            ",abs_time"
54            ",forever"
55            ",hash"
56            ",vsize"
57            ",u16"
58            ",u32"
59            ",u64"
60            ") VALUES "
61            "($1, $2, $3, $4, $5, $6,"
62             "$7, $8, $9);",
63            9, NULL);
64   PREPARE ("test_select",
65            "SELECT"
66            " pub"
67            ",sig"
68            ",abs_time"
69            ",forever"
70            ",hash"
71            ",vsize"
72            ",u16"
73            ",u32"
74            ",u64"
75            " FROM test_pq"
76            " ORDER BY abs_time DESC "
77            " LIMIT 1;",
78            0, NULL);
79   return GNUNET_OK;
80 #undef PREPARE
81 }
82
83
84 /**
85  * Run actual test queries.
86  *
87  * @return 0 on success
88  */
89 static int
90 run_queries (PGconn *conn)
91 {
92   struct GNUNET_CRYPTO_RsaPublicKey *pub;
93   struct GNUNET_CRYPTO_RsaPublicKey *pub2 = NULL;
94   struct GNUNET_CRYPTO_RsaSignature *sig;
95   struct GNUNET_CRYPTO_RsaSignature *sig2 = NULL;
96   struct GNUNET_TIME_Absolute abs_time = GNUNET_TIME_absolute_get ();
97   struct GNUNET_TIME_Absolute abs_time2;
98   struct GNUNET_TIME_Absolute forever = GNUNET_TIME_UNIT_FOREVER_ABS;
99   struct GNUNET_TIME_Absolute forever2;
100   struct GNUNET_HashCode hc;
101   struct GNUNET_HashCode hc2;
102   PGresult *result;
103   int ret;
104   struct GNUNET_CRYPTO_RsaPrivateKey *priv;
105   const char msg[] = "hello";
106   void *msg2;
107   struct GNUNET_HashCode hmsg;
108   size_t msg2_len;
109   uint16_t u16;
110   uint16_t u162;
111   uint32_t u32;
112   uint32_t u322;
113   uint64_t u64;
114   uint64_t u642;
115
116   priv = GNUNET_CRYPTO_rsa_private_key_create (1024);
117   pub = GNUNET_CRYPTO_rsa_private_key_get_public (priv);
118   memset (&hmsg, 42, sizeof (hmsg));
119   sig = GNUNET_CRYPTO_rsa_sign_fdh (priv,
120                                     &hmsg);
121   u16 = 16;
122   u32 = 32;
123   u64 = 64;
124   /* FIXME: test GNUNET_PQ_result_spec_variable_size */
125   {
126     struct GNUNET_PQ_QueryParam params_insert[] = {
127       GNUNET_PQ_query_param_rsa_public_key (pub),
128       GNUNET_PQ_query_param_rsa_signature (sig),
129       GNUNET_PQ_query_param_absolute_time (&abs_time),
130       GNUNET_PQ_query_param_absolute_time (&forever),
131       GNUNET_PQ_query_param_auto_from_type (&hc),
132       GNUNET_PQ_query_param_fixed_size (msg, strlen (msg)),
133       GNUNET_PQ_query_param_uint16 (&u16),
134       GNUNET_PQ_query_param_uint32 (&u32),
135       GNUNET_PQ_query_param_uint64 (&u64),
136       GNUNET_PQ_query_param_end
137     };
138     struct GNUNET_PQ_QueryParam params_select[] = {
139       GNUNET_PQ_query_param_end
140     };
141     struct GNUNET_PQ_ResultSpec results_select[] = {
142       GNUNET_PQ_result_spec_rsa_public_key ("pub", &pub2),
143       GNUNET_PQ_result_spec_rsa_signature ("sig", &sig2),
144       GNUNET_PQ_result_spec_absolute_time ("abs_time", &abs_time2),
145       GNUNET_PQ_result_spec_absolute_time ("forever", &forever2),
146       GNUNET_PQ_result_spec_auto_from_type ("hash", &hc2),
147       GNUNET_PQ_result_spec_variable_size ("vsize", &msg2, &msg2_len),
148       GNUNET_PQ_result_spec_uint16 ("u16", &u162),
149       GNUNET_PQ_result_spec_uint32 ("u32", &u322),
150       GNUNET_PQ_result_spec_uint64 ("u64", &u642),
151       GNUNET_PQ_result_spec_end
152     };
153
154     result = GNUNET_PQ_exec_prepared (conn,
155                                      "test_insert",
156                                      params_insert);
157     if (PGRES_COMMAND_OK != PQresultStatus (result))
158     {
159       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
160                   "Database failure: %s\n",
161                   PQresultErrorMessage (result));
162       PQclear (result);
163       GNUNET_CRYPTO_rsa_signature_free (sig);
164       GNUNET_CRYPTO_rsa_private_key_free (priv);
165       GNUNET_CRYPTO_rsa_public_key_free (pub);
166       return 1;
167     }
168
169     PQclear (result);
170     result = GNUNET_PQ_exec_prepared (conn,
171                                       "test_select",
172                                       params_select);
173     if (1 !=
174         PQntuples (result))
175     {
176       GNUNET_break (0);
177       PQclear (result);
178       GNUNET_CRYPTO_rsa_signature_free (sig);
179       GNUNET_CRYPTO_rsa_private_key_free (priv);
180       GNUNET_CRYPTO_rsa_public_key_free (pub);
181       return 1;
182     }
183     ret = GNUNET_PQ_extract_result (result,
184                                    results_select,
185                                    0);
186     GNUNET_break (GNUNET_YES == ret);
187     GNUNET_break (abs_time.abs_value_us == abs_time2.abs_value_us);
188     GNUNET_break (forever.abs_value_us == forever2.abs_value_us);
189     GNUNET_break (0 ==
190                   memcmp (&hc,
191                           &hc2,
192                           sizeof (struct GNUNET_HashCode)));
193     GNUNET_break (0 ==
194                   GNUNET_CRYPTO_rsa_signature_cmp (sig,
195                                                    sig2));
196     GNUNET_break (0 ==
197                   GNUNET_CRYPTO_rsa_public_key_cmp (pub,
198                                                     pub2));
199     GNUNET_break (strlen (msg) == msg2_len);
200     GNUNET_break (0 ==
201                   strncmp (msg,
202                            msg2,
203                            msg2_len));
204     GNUNET_break (16 == u162);
205     GNUNET_break (32 == u322);
206     GNUNET_break (64 == u642);
207     GNUNET_PQ_cleanup_result (results_select);
208     PQclear (result);
209   }
210   GNUNET_CRYPTO_rsa_signature_free (sig);
211   GNUNET_CRYPTO_rsa_private_key_free (priv);
212   GNUNET_CRYPTO_rsa_public_key_free (pub);
213   if (GNUNET_OK != ret)
214     return 1;
215
216   return 0;
217 }
218
219
220 int
221 main(int argc,
222      const char *const argv[])
223 {
224   PGconn *conn;
225   PGresult *result;
226   int ret;
227
228   GNUNET_log_setup ("test-pq",
229                     "WARNING",
230                     NULL);
231   conn = PQconnectdb ("postgres:///gnunetcheck");
232   if (CONNECTION_OK != PQstatus (conn))
233   {
234     fprintf (stderr,
235              "Cannot run test, database connection failed: %s\n",
236              PQerrorMessage (conn));
237     GNUNET_break (0);
238     PQfinish (conn);
239     return 0; /* We ignore this type of error... */
240   }
241
242   result = PQexec (conn,
243                    "CREATE TEMPORARY TABLE IF NOT EXISTS test_pq ("
244                    " pub BYTEA NOT NULL"
245                    ",sig BYTEA NOT NULL"
246                    ",abs_time INT8 NOT NULL"
247                    ",forever INT8 NOT NULL"
248                    ",hash BYTEA NOT NULL CHECK(LENGTH(hash)=64)"
249                    ",vsize VARCHAR NOT NULL"
250                    ",u16 INT2 NOT NULL"
251                    ",u32 INT4 NOT NULL"
252                    ",u64 INT8 NOT NULL"
253                    ")");
254   if (PGRES_COMMAND_OK != PQresultStatus (result))
255   {
256     fprintf (stderr,
257              "Failed to create table: %s\n",
258              PQerrorMessage (conn));
259     PQclear (result);
260     PQfinish (conn);
261     return 1;
262   }
263   PQclear (result);
264   if (GNUNET_OK !=
265       postgres_prepare (conn))
266   {
267     GNUNET_break (0);
268     PQfinish (conn);
269     return 1;
270   }
271   ret = run_queries (conn);
272   result = PQexec (conn,
273                    "DROP TABLE test_pq");
274   if (PGRES_COMMAND_OK != PQresultStatus (result))
275   {
276     fprintf (stderr,
277              "Failed to create table: %s\n",
278              PQerrorMessage (conn));
279     PQclear (result);
280     PQfinish (conn);
281     return 1;
282   }
283   PQclear (result);
284   PQfinish (conn);
285   return ret;
286 }
287
288
289 /* end of test_pq.c */