test_aggregation_transient.c (13104B)
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 &total)); 87 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 88 TALER_EXCHANGEDB_get_aggregation_transient_by_wtid ( 89 pg, 90 &account.h_full, 91 &wtid, 92 &total, 93 &requirement_row)); 94 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 95 TALER_EXCHANGEDB_get_aggregation_transient_by_normalized_payto ( 96 pg, 97 &account.h_normalized, 98 &payto_uri, 99 &wtid, 100 &merchant_pub, 101 &total)); 102 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 103 TALER_EXCHANGEDB_update_aggregation_transient (pg, 104 &account.h_full, 105 &wtid, 106 0, 107 &one)); 108 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 109 TALER_EXCHANGEDB_delete_aggregation_transient (pg, 110 &account.h_full, 111 &wtid)); 112 FAILIF (0 != TDB_count (pg, 113 "FROM aggregation_transient")); 114 return 0; 115 } 116 117 118 /** 119 * An inserted row is found by all three lookups. 120 * 121 * @param pg the database context 122 * @return 0 on success 123 */ 124 static int 125 check_insert_and_lookup (struct TALER_EXCHANGEDB_PostgresContext *pg) 126 { 127 struct TALER_MerchantPublicKeyP merchant_pub; 128 struct TALER_MerchantPublicKeyP got_merchant; 129 struct TALER_WireTransferIdentifierRawP wtid; 130 struct TALER_WireTransferIdentifierRawP got_wtid; 131 struct TALER_Amount total = TDB_amount ("3"); 132 struct TALER_Amount got; 133 struct TALER_FullPayto payto_uri = { NULL }; 134 uint64_t requirement_row = 42; 135 136 TDB_FILL (merchant_pub, 137 10); 138 TDB_FILL (wtid, 139 10); 140 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 141 TALER_EXCHANGEDB_insert_aggregation_transient (pg, 142 &account.h_full, 143 SECTION, 144 &merchant_pub, 145 &wtid, 146 0, 147 &total)); 148 FAILIF (1 != TDB_count (pg, 149 "FROM aggregation_transient")); 150 151 /* by (account, merchant, exchange account) */ 152 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 153 TALER_EXCHANGEDB_get_aggregation_transient (pg, 154 &account.h_full, 155 &merchant_pub, 156 SECTION, 157 &got_wtid, 158 &got)); 159 FAILIF (0 != GNUNET_memcmp (&got_wtid, 160 &wtid)); 161 FAILIF (0 != TALER_amount_cmp (&got, 162 &total)); 163 164 /* by (account, wtid) */ 165 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 166 TALER_EXCHANGEDB_get_aggregation_transient_by_wtid ( 167 pg, 168 &account.h_full, 169 &wtid, 170 &got, 171 &requirement_row)); 172 FAILIF (0 != TALER_amount_cmp (&got, 173 &total)); 174 /* no legitimization reason was recorded */ 175 FAILIF (0 != requirement_row); 176 177 /* by normalized account */ 178 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 179 TALER_EXCHANGEDB_get_aggregation_transient_by_normalized_payto ( 180 pg, 181 &account.h_normalized, 182 &payto_uri, 183 &got_wtid, 184 &got_merchant, 185 &got)); 186 FAILIF_C (0 != strcmp (payto_uri.full_payto, 187 account.payto.full_payto), 188 GNUNET_free (payto_uri.full_payto)); 189 GNUNET_free (payto_uri.full_payto); 190 FAILIF (0 != GNUNET_memcmp (&got_merchant, 191 &merchant_pub)); 192 FAILIF (0 != GNUNET_memcmp (&got_wtid, 193 &wtid)); 194 195 /* a different merchant on the same account has nothing */ 196 { 197 struct TALER_MerchantPublicKeyP other; 198 199 TDB_FILL (other, 200 99); 201 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 202 TALER_EXCHANGEDB_get_aggregation_transient (pg, 203 &account.h_full, 204 &other, 205 SECTION, 206 &got_wtid, 207 &got)); 208 } 209 /* and neither does a different exchange bank account */ 210 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 211 TALER_EXCHANGEDB_get_aggregation_transient (pg, 212 &account.h_full, 213 &merchant_pub, 214 "exchange-account-2", 215 &got_wtid, 216 &got)); 217 return 0; 218 } 219 220 221 /** 222 * Updating a row changes the amount and the legitimization reason. 223 * 224 * @param pg the database context 225 * @return 0 on success 226 */ 227 static int 228 check_update (struct TALER_EXCHANGEDB_PostgresContext *pg) 229 { 230 struct TALER_MerchantPublicKeyP merchant_pub; 231 struct TALER_WireTransferIdentifierRawP wtid; 232 struct TALER_WireTransferIdentifierRawP got_wtid; 233 struct TALER_Amount total = TDB_amount ("7"); 234 struct TALER_Amount got; 235 uint64_t requirement_row = 0; 236 237 TDB_FILL (merchant_pub, 238 10); 239 TDB_FILL (wtid, 240 10); 241 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 242 TALER_EXCHANGEDB_update_aggregation_transient (pg, 243 &account.h_full, 244 &wtid, 245 5, 246 &total)); 247 FAILIF (1 != TDB_count (pg, 248 "FROM aggregation_transient")); 249 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 250 TALER_EXCHANGEDB_get_aggregation_transient (pg, 251 &account.h_full, 252 &merchant_pub, 253 SECTION, 254 &got_wtid, 255 &got)); 256 FAILIF (0 != TALER_amount_cmp (&got, 257 &total)); 258 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 259 TALER_EXCHANGEDB_get_aggregation_transient_by_wtid ( 260 pg, 261 &account.h_full, 262 &wtid, 263 &got, 264 &requirement_row)); 265 FAILIF (5 != requirement_row); 266 267 /* a wire transfer identifier that is not on file is not created */ 268 { 269 struct TALER_WireTransferIdentifierRawP other; 270 271 TDB_FILL (other, 272 98); 273 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 274 TALER_EXCHANGEDB_update_aggregation_transient (pg, 275 &account.h_full, 276 &other, 277 0, 278 &total)); 279 FAILIF (1 != TDB_count (pg, 280 "FROM aggregation_transient")); 281 } 282 return 0; 283 } 284 285 286 /** 287 * Deleting a row removes it, and a second delete does nothing. 288 * 289 * @param pg the database context 290 * @return 0 on success 291 */ 292 static int 293 check_delete (struct TALER_EXCHANGEDB_PostgresContext *pg) 294 { 295 struct TALER_MerchantPublicKeyP merchant_pub; 296 struct TALER_WireTransferIdentifierRawP wtid; 297 struct TALER_Amount got; 298 299 TDB_FILL (merchant_pub, 300 10); 301 TDB_FILL (wtid, 302 10); 303 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 304 TALER_EXCHANGEDB_delete_aggregation_transient (pg, 305 &account.h_full, 306 &wtid)); 307 FAILIF (0 != TDB_count (pg, 308 "FROM aggregation_transient")); 309 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 310 TALER_EXCHANGEDB_delete_aggregation_transient (pg, 311 &account.h_full, 312 &wtid)); 313 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 314 TALER_EXCHANGEDB_get_aggregation_transient (pg, 315 &account.h_full, 316 &merchant_pub, 317 SECTION, 318 &wtid, 319 &got)); 320 return 0; 321 } 322 323 324 /** 325 * The checks to run, in order. 326 */ 327 static const struct TDB_Test tests[] = { 328 { "aggregation-transient-empty", 329 &check_empty }, 330 { "aggregation-transient-insert-and-lookup", 331 &check_insert_and_lookup }, 332 { "aggregation-transient-update", 333 &check_update }, 334 { "aggregation-transient-delete", 335 &check_delete }, 336 { NULL, NULL } 337 }; 338 339 340 int 341 main (int argc, 342 char *const *argv) 343 { 344 int ret; 345 346 ret = TDB_main (argc, 347 argv, 348 "test-aggregation-transient", 349 "Tests for the exchangedb `aggregation_transient' table", 350 tests); 351 TDB_account_free (&account); 352 return ret; 353 } 354 355 356 /* end of test_aggregation_transient.c */