test_aggregation_transient.c (13796B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2026 Taler Systems SA 4 5 TALER 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 TALER 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 TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 /** 17 * @file exchangedb/test_aggregation_transient.c 18 * @brief tests for the exchangedb functions whose primary table is 19 * `aggregation_transient` 20 * @author Christian Grothoff 21 * 22 * Covers #TALER_EXCHANGEDB_insert_aggregation_transient(), 23 * #TALER_EXCHANGEDB_update_aggregation_transient(), 24 * #TALER_EXCHANGEDB_delete_aggregation_transient(), 25 * #TALER_EXCHANGEDB_get_aggregation_transient(), 26 * #TALER_EXCHANGEDB_get_aggregation_transient_by_wtid() and 27 * #TALER_EXCHANGEDB_get_aggregation_transient_by_normalized_payto(). 28 * 29 * The table holds what the aggregator decided to hold back for later; it 30 * is updated in place and deleted on payout, so it has no serial ID. It 31 * references `wire_targets`, which TDB_account() creates. The three 32 * lookups reach the row by three different keys, which is what the checks 33 * exercise. 34 */ 35 #include "test_common.h" 36 #include "exchange-database/delete_aggregation_transient.h" 37 #include "exchange-database/get_aggregation_transient.h" 38 #include "exchange-database/get_aggregation_transient_by_normalized_payto.h" 39 #include "exchange-database/get_aggregation_transient_by_wtid.h" 40 #include "exchange-database/insert_aggregation_transient.h" 41 #include "exchange-database/update_aggregation_transient.h" 42 43 44 /** 45 * Exchange bank account the checks aggregate for. 46 */ 47 #define SECTION "exchange-account-1" 48 49 50 /** 51 * Account the merchants of the checks are paid at. 52 */ 53 static struct TDB_Account account; 54 55 56 /** 57 * Nothing is found while the table is empty, and updating or deleting a 58 * row that is not there does nothing. 59 * 60 * @param pg the database context 61 * @return 0 on success 62 */ 63 static int 64 check_empty (struct TALER_EXCHANGEDB_PostgresContext *pg) 65 { 66 struct TALER_MerchantPublicKeyP merchant_pub; 67 struct TALER_WireTransferIdentifierRawP wtid; 68 struct TALER_Amount total; 69 struct TALER_Amount one = TDB_amount ("1"); 70 struct TALER_FullPayto payto_uri = { NULL }; 71 uint64_t requirement_row; 72 73 TDB_account (pg, 74 10, 75 &account); 76 TDB_FILL (merchant_pub, 77 1); 78 TDB_FILL (wtid, 79 1); 80 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 81 TALER_EXCHANGEDB_get_aggregation_transient (pg, 82 &account.h_full, 83 &merchant_pub, 84 SECTION, 85 &wtid, 86 &requirement_row, 87 &total)); 88 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 89 TALER_EXCHANGEDB_get_aggregation_transient_by_wtid ( 90 pg, 91 &account.h_full, 92 &wtid, 93 &total, 94 &requirement_row)); 95 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 96 TALER_EXCHANGEDB_get_aggregation_transient_by_normalized_payto ( 97 pg, 98 &account.h_normalized, 99 &payto_uri, 100 &wtid, 101 &merchant_pub, 102 &total)); 103 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 104 TALER_EXCHANGEDB_update_aggregation_transient (pg, 105 &account.h_full, 106 &wtid, 107 0, 108 &one)); 109 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 110 TALER_EXCHANGEDB_delete_aggregation_transient (pg, 111 &account.h_full, 112 &wtid)); 113 FAILIF (0 != TDB_count (pg, 114 "FROM aggregation_transient")); 115 return 0; 116 } 117 118 119 /** 120 * An inserted row is found by all three lookups. 121 * 122 * @param pg the database context 123 * @return 0 on success 124 */ 125 static int 126 check_insert_and_lookup (struct TALER_EXCHANGEDB_PostgresContext *pg) 127 { 128 struct TALER_MerchantPublicKeyP merchant_pub; 129 struct TALER_MerchantPublicKeyP got_merchant; 130 struct TALER_WireTransferIdentifierRawP wtid; 131 struct TALER_WireTransferIdentifierRawP got_wtid; 132 struct TALER_Amount total = TDB_amount ("3"); 133 struct TALER_Amount got; 134 struct TALER_FullPayto payto_uri = { NULL }; 135 uint64_t requirement_row = 42; 136 137 TDB_FILL (merchant_pub, 138 10); 139 TDB_FILL (wtid, 140 10); 141 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 142 TALER_EXCHANGEDB_insert_aggregation_transient (pg, 143 &account.h_full, 144 SECTION, 145 &merchant_pub, 146 &wtid, 147 0, 148 &total)); 149 FAILIF (1 != TDB_count (pg, 150 "FROM aggregation_transient")); 151 152 /* by (account, merchant, exchange account) */ 153 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 154 TALER_EXCHANGEDB_get_aggregation_transient (pg, 155 &account.h_full, 156 &merchant_pub, 157 SECTION, 158 &got_wtid, 159 &requirement_row, 160 &got)); 161 FAILIF (0 != GNUNET_memcmp (&got_wtid, 162 &wtid)); 163 FAILIF (0 != TALER_amount_cmp (&got, 164 &total)); 165 /* no legitimization reason was recorded */ 166 FAILIF (0 != requirement_row); 167 168 /* by (account, wtid) */ 169 requirement_row = 42; 170 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 171 TALER_EXCHANGEDB_get_aggregation_transient_by_wtid ( 172 pg, 173 &account.h_full, 174 &wtid, 175 &got, 176 &requirement_row)); 177 FAILIF (0 != TALER_amount_cmp (&got, 178 &total)); 179 /* no legitimization reason was recorded */ 180 FAILIF (0 != requirement_row); 181 182 /* by normalized account */ 183 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 184 TALER_EXCHANGEDB_get_aggregation_transient_by_normalized_payto ( 185 pg, 186 &account.h_normalized, 187 &payto_uri, 188 &got_wtid, 189 &got_merchant, 190 &got)); 191 FAILIF_C (0 != strcmp (payto_uri.full_payto, 192 account.payto.full_payto), 193 GNUNET_free (payto_uri.full_payto)); 194 GNUNET_free (payto_uri.full_payto); 195 FAILIF (0 != GNUNET_memcmp (&got_merchant, 196 &merchant_pub)); 197 FAILIF (0 != GNUNET_memcmp (&got_wtid, 198 &wtid)); 199 200 /* a different merchant on the same account has nothing */ 201 { 202 struct TALER_MerchantPublicKeyP other; 203 204 TDB_FILL (other, 205 99); 206 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 207 TALER_EXCHANGEDB_get_aggregation_transient (pg, 208 &account.h_full, 209 &other, 210 SECTION, 211 &got_wtid, 212 &requirement_row, 213 &got)); 214 } 215 /* and neither does a different exchange bank account */ 216 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 217 TALER_EXCHANGEDB_get_aggregation_transient (pg, 218 &account.h_full, 219 &merchant_pub, 220 "exchange-account-2", 221 &got_wtid, 222 &requirement_row, 223 &got)); 224 return 0; 225 } 226 227 228 /** 229 * Updating a row changes the amount and the legitimization reason. 230 * 231 * @param pg the database context 232 * @return 0 on success 233 */ 234 static int 235 check_update (struct TALER_EXCHANGEDB_PostgresContext *pg) 236 { 237 struct TALER_MerchantPublicKeyP merchant_pub; 238 struct TALER_WireTransferIdentifierRawP wtid; 239 struct TALER_WireTransferIdentifierRawP got_wtid; 240 struct TALER_Amount total = TDB_amount ("7"); 241 struct TALER_Amount got; 242 uint64_t requirement_row = 0; 243 244 TDB_FILL (merchant_pub, 245 10); 246 TDB_FILL (wtid, 247 10); 248 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 249 TALER_EXCHANGEDB_update_aggregation_transient (pg, 250 &account.h_full, 251 &wtid, 252 5, 253 &total)); 254 FAILIF (1 != TDB_count (pg, 255 "FROM aggregation_transient")); 256 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 257 TALER_EXCHANGEDB_get_aggregation_transient (pg, 258 &account.h_full, 259 &merchant_pub, 260 SECTION, 261 &got_wtid, 262 &requirement_row, 263 &got)); 264 FAILIF (0 != TALER_amount_cmp (&got, 265 &total)); 266 /* the legitimization reason is read back, so re-parking keeps it */ 267 FAILIF (5 != requirement_row); 268 requirement_row = 0; 269 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 270 TALER_EXCHANGEDB_get_aggregation_transient_by_wtid ( 271 pg, 272 &account.h_full, 273 &wtid, 274 &got, 275 &requirement_row)); 276 FAILIF (5 != requirement_row); 277 278 /* a wire transfer identifier that is not on file is not created */ 279 { 280 struct TALER_WireTransferIdentifierRawP other; 281 282 TDB_FILL (other, 283 98); 284 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 285 TALER_EXCHANGEDB_update_aggregation_transient (pg, 286 &account.h_full, 287 &other, 288 0, 289 &total)); 290 FAILIF (1 != TDB_count (pg, 291 "FROM aggregation_transient")); 292 } 293 return 0; 294 } 295 296 297 /** 298 * Deleting a row removes it, and a second delete does nothing. 299 * 300 * @param pg the database context 301 * @return 0 on success 302 */ 303 static int 304 check_delete (struct TALER_EXCHANGEDB_PostgresContext *pg) 305 { 306 struct TALER_MerchantPublicKeyP merchant_pub; 307 struct TALER_WireTransferIdentifierRawP wtid; 308 struct TALER_Amount got; 309 uint64_t requirement_row; 310 311 TDB_FILL (merchant_pub, 312 10); 313 TDB_FILL (wtid, 314 10); 315 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 316 TALER_EXCHANGEDB_delete_aggregation_transient (pg, 317 &account.h_full, 318 &wtid)); 319 FAILIF (0 != TDB_count (pg, 320 "FROM aggregation_transient")); 321 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 322 TALER_EXCHANGEDB_delete_aggregation_transient (pg, 323 &account.h_full, 324 &wtid)); 325 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 326 TALER_EXCHANGEDB_get_aggregation_transient (pg, 327 &account.h_full, 328 &merchant_pub, 329 SECTION, 330 &wtid, 331 &requirement_row, 332 &got)); 333 return 0; 334 } 335 336 337 /** 338 * The checks to run, in order. 339 */ 340 static const struct TDB_Test tests[] = { 341 { "aggregation-transient-empty", 342 &check_empty }, 343 { "aggregation-transient-insert-and-lookup", 344 &check_insert_and_lookup }, 345 { "aggregation-transient-update", 346 &check_update }, 347 { "aggregation-transient-delete", 348 &check_delete }, 349 { NULL, NULL } 350 }; 351 352 353 int 354 main (int argc, 355 char *const *argv) 356 { 357 int ret; 358 359 ret = TDB_main (argc, 360 argv, 361 "test-aggregation-transient", 362 "Tests for the exchangedb `aggregation_transient' table", 363 tests); 364 TDB_account_free (&account); 365 return ret; 366 } 367 368 369 /* end of test_aggregation_transient.c */