test_partners.c (6085B)
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_partners.c 18 * @brief tests for the exchangedb functions whose primary table is 19 * `partners` 20 * @author Christian Grothoff 21 * 22 * Covers #TALER_EXCHANGEDB_insert_partner(). It is the only exported 23 * function that writes the table; the rows are read back by the purse 24 * machinery, which is covered in test_purse_merges.c and 25 * test_purse_deposits.c. 26 * 27 * `partners` has no foreign keys. The insert is ON CONFLICT DO NOTHING, 28 * so re-inserting the same (key, validity period) is a no-op rather than a 29 * failure. 30 */ 31 #include "test_common.h" 32 #include "exchange-database/insert_partner.h" 33 34 35 /** 36 * Build a timestamp from a number of seconds since the epoch. 37 * 38 * @param secs seconds since the epoch 39 * @return the timestamp 40 */ 41 static struct GNUNET_TIME_Timestamp 42 ts (uint64_t secs) 43 { 44 struct GNUNET_TIME_Absolute abs = { 45 .abs_value_us = secs * 1000LLU * 1000LLU 46 }; 47 48 return GNUNET_TIME_absolute_to_timestamp (abs); 49 } 50 51 52 /** 53 * Insert a partner exchange. 54 * 55 * @param pg the database context 56 * @param seed seed for the partner's key and signature 57 * @param from start of the validity period 58 * @param until end of the validity period 59 * @param url base URL of the partner 60 * @return transaction status 61 */ 62 static enum GNUNET_DB_QueryStatus 63 add_partner (struct TALER_EXCHANGEDB_PostgresContext *pg, 64 uint32_t seed, 65 uint64_t from, 66 uint64_t until, 67 const char *url) 68 { 69 struct TALER_MasterPublicKeyP master_pub; 70 struct TALER_MasterSignatureP master_sig; 71 struct TALER_Amount wad_fee = TDB_amount ("0.05"); 72 73 TDB_FILL (master_pub, 74 seed); 75 TDB_FILL (master_sig, 76 seed); 77 return TALER_EXCHANGEDB_insert_partner (pg, 78 &master_pub, 79 ts (from), 80 ts (until), 81 GNUNET_TIME_UNIT_HOURS, 82 &wad_fee, 83 url, 84 &master_sig); 85 } 86 87 88 /** 89 * Inserting a partner stores exactly the row we asked for. 90 * 91 * @param pg the database context 92 * @return 0 on success 93 */ 94 static int 95 check_insert (struct TALER_EXCHANGEDB_PostgresContext *pg) 96 { 97 struct TALER_MasterPublicKeyP master_pub; 98 struct TALER_Amount wad_fee = TDB_amount ("0.05"); 99 char *hex; 100 101 FAILIF (0 != TDB_count (pg, 102 "FROM partners")); 103 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 104 add_partner (pg, 105 10, 106 1600000000, 107 1700000000, 108 "https://partner.example/")); 109 TDB_FILL (master_pub, 110 10); 111 hex = TDB_hex (&master_pub, 112 sizeof (master_pub)); 113 FAILIF_C (1 != TDB_count (pg, 114 "FROM partners" 115 " WHERE partner_master_pub=decode('%s','hex')" 116 " AND partner_base_url='https://partner.example/'" 117 " AND wad_fee=ROW(%llu,%u)::taler_amount" 118 " AND start_date=%llu" 119 " AND end_date=%llu", 120 hex, 121 (unsigned long long) wad_fee.value, 122 (unsigned int) wad_fee.fraction, 123 (unsigned long long) 1600000000000000LLU, 124 (unsigned long long) 1700000000000000LLU), 125 GNUNET_free (hex)); 126 GNUNET_free (hex); 127 return 0; 128 } 129 130 131 /** 132 * Re-inserting the identical row is a no-op, while a different validity 133 * period for the same key is a new row. 134 * 135 * @param pg the database context 136 * @return 0 on success 137 */ 138 static int 139 check_conflict (struct TALER_EXCHANGEDB_PostgresContext *pg) 140 { 141 /* identical to what check_insert() stored */ 142 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 143 add_partner (pg, 144 10, 145 1600000000, 146 1700000000, 147 "https://partner.example/")); 148 FAILIF (1 != TDB_count (pg, 149 "FROM partners")); 150 /* a later period for the same partner is a separate row */ 151 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 152 add_partner (pg, 153 10, 154 1700000000, 155 1800000000, 156 "https://partner.example/")); 157 FAILIF (2 != TDB_count (pg, 158 "FROM partners")); 159 /* and so is a different partner */ 160 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 161 add_partner (pg, 162 11, 163 1600000000, 164 1700000000, 165 "https://other.example/")); 166 FAILIF (3 != TDB_count (pg, 167 "FROM partners")); 168 return 0; 169 } 170 171 172 /** 173 * The checks to run, in order. 174 */ 175 static const struct TDB_Test tests[] = { 176 { "partners-insert", 177 &check_insert }, 178 { "partners-conflict", 179 &check_conflict }, 180 { NULL, NULL } 181 }; 182 183 184 int 185 main (int argc, 186 char *const *argv) 187 { 188 return TDB_main (argc, 189 argv, 190 "test-partners", 191 "Tests for the exchangedb `partners' table", 192 tests); 193 } 194 195 196 /* end of test_partners.c */