test_auditor_denom_sigs.c (11807B)
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_auditor_denom_sigs.c 18 * @brief tests for the exchangedb functions whose primary table is 19 * `auditor_denom_sigs` 20 * @author Christian Grothoff 21 * 22 * Covers #TALER_EXCHANGEDB_insert_auditor_denom_sig(), 23 * #TALER_EXCHANGEDB_get_auditor_denom_sig() and 24 * #TALER_EXCHANGEDB_iterate_auditor_denominations(). 25 * 26 * The table references `auditors` and `denominations`, and the insert 27 * resolves both by their natural keys inside the statement -- so an unknown 28 * auditor or denomination has to come back as "nothing inserted". Fixtures 29 * come from #TALER_EXCHANGEDB_insert_auditor() and TDB_denom(), whose own 30 * tables are covered by test_auditors.c and test_denominations.c. 31 */ 32 #include "test_common.h" 33 #include "exchange-database/insert_auditor.h" 34 #include "exchange-database/update_auditor.h" 35 #include "exchange-database/insert_auditor_denom_sig.h" 36 #include "exchange-database/get_auditor_denom_sig.h" 37 #include "exchange-database/iterate_auditor_denominations.h" 38 39 40 /** 41 * Closure for #count_cb(). 42 */ 43 struct CountContext 44 { 45 /** 46 * Auditor we are looking for. 47 */ 48 const struct TALER_AuditorPublicKeyP *auditor_pub; 49 50 /** 51 * Denomination we are looking for. 52 */ 53 const struct TALER_DenominationHashP *h_denom_pub; 54 55 /** 56 * How many rows did the callback see in total? 57 */ 58 unsigned int total; 59 60 /** 61 * How many times did we see the pair we are after? 62 */ 63 unsigned int matched; 64 65 /** 66 * Signature reported for that pair. 67 */ 68 struct TALER_AuditorSignatureP auditor_sig; 69 }; 70 71 72 /** 73 * Callback for #TALER_EXCHANGEDB_iterate_auditor_denominations(). 74 * 75 * @param cls a `struct CountContext *` 76 * @param auditor_pub public key of the auditor 77 * @param h_denom_pub denomination audited by @a auditor_pub 78 * @param auditor_sig the auditor's signature 79 */ 80 static void 81 count_cb (void *cls, 82 const struct TALER_AuditorPublicKeyP *auditor_pub, 83 const struct TALER_DenominationHashP *h_denom_pub, 84 const struct TALER_AuditorSignatureP *auditor_sig) 85 { 86 struct CountContext *ctx = cls; 87 88 ctx->total++; 89 if ( (0 != GNUNET_memcmp (auditor_pub, 90 ctx->auditor_pub)) || 91 (0 != GNUNET_memcmp (h_denom_pub, 92 ctx->h_denom_pub)) ) 93 return; 94 ctx->matched++; 95 ctx->auditor_sig = *auditor_sig; 96 } 97 98 99 /** 100 * Neither half of the pair existing means nothing is inserted and nothing 101 * is found. 102 * 103 * @param pg the database context 104 * @return 0 on success 105 */ 106 static int 107 check_unknown_references (struct TALER_EXCHANGEDB_PostgresContext *pg) 108 { 109 struct TALER_AuditorPublicKeyP auditor_pub; 110 struct TALER_DenominationHashP h_denom_pub; 111 struct TALER_AuditorSignatureP auditor_sig; 112 struct TALER_AuditorSignatureP got; 113 struct TDB_Denom denom; 114 115 TDB_FILL (auditor_pub, 116 1); 117 TDB_FILL (h_denom_pub, 118 1); 119 TDB_FILL (auditor_sig, 120 1); 121 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 122 TALER_EXCHANGEDB_get_auditor_denom_sig (pg, 123 &h_denom_pub, 124 &auditor_pub, 125 &got)); 126 /* neither the auditor nor the denomination exist */ 127 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 128 TALER_EXCHANGEDB_insert_auditor_denom_sig (pg, 129 &h_denom_pub, 130 &auditor_pub, 131 &auditor_sig)); 132 /* the denomination exists, the auditor does not */ 133 TDB_denom (pg, 134 10, 135 "5", 136 "0.1", 137 &denom); 138 FAILIF_C (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 139 TALER_EXCHANGEDB_insert_auditor_denom_sig (pg, 140 &denom.h_denom_pub, 141 &auditor_pub, 142 &auditor_sig), 143 TDB_denom_free (&denom)); 144 /* the auditor exists, the denomination does not */ 145 FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 146 TALER_EXCHANGEDB_insert_auditor (pg, 147 &auditor_pub, 148 "https://auditor.example/", 149 "The Auditor", 150 GNUNET_TIME_timestamp_get ()), 151 TDB_denom_free (&denom)); 152 FAILIF_C (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 153 TALER_EXCHANGEDB_insert_auditor_denom_sig (pg, 154 &h_denom_pub, 155 &auditor_pub, 156 &auditor_sig), 157 TDB_denom_free (&denom)); 158 FAILIF_C (0 != TDB_count (pg, 159 "FROM auditor_denom_sigs"), 160 TDB_denom_free (&denom)); 161 TDB_denom_free (&denom); 162 return 0; 163 } 164 165 166 /** 167 * With both halves present the signature is stored, found and iterated; 168 * a repeated insert is a no-op. 169 * 170 * @param pg the database context 171 * @return 0 on success 172 */ 173 static int 174 check_insert_and_lookup (struct TALER_EXCHANGEDB_PostgresContext *pg) 175 { 176 struct TALER_AuditorPublicKeyP auditor_pub; 177 struct TALER_AuditorSignatureP auditor_sig; 178 struct TALER_AuditorSignatureP other_sig; 179 struct TALER_AuditorSignatureP got; 180 struct TDB_Denom denom; 181 struct CountContext ctx; 182 183 /* the auditor and denomination from the previous check */ 184 TDB_FILL (auditor_pub, 185 1); 186 TDB_FILL (auditor_sig, 187 1); 188 TDB_FILL (other_sig, 189 77); 190 TDB_denom (pg, 191 10, 192 "5", 193 "0.1", 194 &denom); 195 /* TDB_denom() with the same seed builds the same key, so the row is the 196 one the previous check created; that is exactly what we want here. */ 197 FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 198 TALER_EXCHANGEDB_insert_auditor_denom_sig (pg, 199 &denom.h_denom_pub, 200 &auditor_pub, 201 &auditor_sig), 202 TDB_denom_free (&denom)); 203 memset (&got, 204 0, 205 sizeof (got)); 206 FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 207 TALER_EXCHANGEDB_get_auditor_denom_sig (pg, 208 &denom.h_denom_pub, 209 &auditor_pub, 210 &got), 211 TDB_denom_free (&denom)); 212 FAILIF_C (0 != GNUNET_memcmp (&got, 213 &auditor_sig), 214 TDB_denom_free (&denom)); 215 216 /* re-inserting with a different signature does nothing (ON CONFLICT DO 217 NOTHING), and in particular does not overwrite the stored one */ 218 FAILIF_C (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 219 TALER_EXCHANGEDB_insert_auditor_denom_sig (pg, 220 &denom.h_denom_pub, 221 &auditor_pub, 222 &other_sig), 223 TDB_denom_free (&denom)); 224 FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 225 TALER_EXCHANGEDB_get_auditor_denom_sig (pg, 226 &denom.h_denom_pub, 227 &auditor_pub, 228 &got), 229 TDB_denom_free (&denom)); 230 FAILIF_C (0 != GNUNET_memcmp (&got, 231 &auditor_sig), 232 TDB_denom_free (&denom)); 233 234 memset (&ctx, 235 0, 236 sizeof (ctx)); 237 ctx.auditor_pub = &auditor_pub; 238 ctx.h_denom_pub = &denom.h_denom_pub; 239 FAILIF_C (0 >= 240 TALER_EXCHANGEDB_iterate_auditor_denominations (pg, 241 &count_cb, 242 &ctx), 243 TDB_denom_free (&denom)); 244 FAILIF_C (1 != ctx.matched, 245 TDB_denom_free (&denom)); 246 FAILIF_C (0 != GNUNET_memcmp (&ctx.auditor_sig, 247 &auditor_sig), 248 TDB_denom_free (&denom)); 249 TDB_denom_free (&denom); 250 return 0; 251 } 252 253 254 /** 255 * A disabled auditor keeps its rows but drops out of the iterator. 256 * 257 * @param pg the database context 258 * @return 0 on success 259 */ 260 static int 261 check_disabled_auditor (struct TALER_EXCHANGEDB_PostgresContext *pg) 262 { 263 struct TALER_AuditorPublicKeyP auditor_pub; 264 struct TALER_AuditorSignatureP got; 265 struct TDB_Denom denom; 266 struct CountContext ctx; 267 268 TDB_FILL (auditor_pub, 269 1); 270 TDB_denom (pg, 271 10, 272 "5", 273 "0.1", 274 &denom); 275 FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 276 TALER_EXCHANGEDB_update_auditor (pg, 277 &auditor_pub, 278 "https://auditor.example/", 279 "The Auditor", 280 GNUNET_TIME_timestamp_get (), 281 false), 282 TDB_denom_free (&denom)); 283 memset (&ctx, 284 0, 285 sizeof (ctx)); 286 ctx.auditor_pub = &auditor_pub; 287 ctx.h_denom_pub = &denom.h_denom_pub; 288 FAILIF_C (0 > 289 TALER_EXCHANGEDB_iterate_auditor_denominations (pg, 290 &count_cb, 291 &ctx), 292 TDB_denom_free (&denom)); 293 FAILIF_C (0 != ctx.matched, 294 TDB_denom_free (&denom)); 295 FAILIF_C (0 != ctx.total, 296 TDB_denom_free (&denom)); 297 /* the row itself is untouched, and the direct lookup ignores is_active */ 298 FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 299 TALER_EXCHANGEDB_get_auditor_denom_sig (pg, 300 &denom.h_denom_pub, 301 &auditor_pub, 302 &got), 303 TDB_denom_free (&denom)); 304 FAILIF_C (1 != TDB_count (pg, 305 "FROM auditor_denom_sigs"), 306 TDB_denom_free (&denom)); 307 TDB_denom_free (&denom); 308 return 0; 309 } 310 311 312 /** 313 * The checks to run, in order. 314 */ 315 static const struct TDB_Test tests[] = { 316 { "auditor-denom-sigs-unknown-references", 317 &check_unknown_references }, 318 { "auditor-denom-sigs-insert-and-lookup", 319 &check_insert_and_lookup }, 320 { "auditor-denom-sigs-disabled-auditor", 321 &check_disabled_auditor }, 322 { NULL, NULL } 323 }; 324 325 326 int 327 main (int argc, 328 char *const *argv) 329 { 330 return TDB_main (argc, 331 argv, 332 "test-auditor-denom-sigs", 333 "Tests for the exchangedb `auditor_denom_sigs' table", 334 tests); 335 } 336 337 338 /* end of test_auditor_denom_sigs.c */