test_revolving_work_shards.c (9879B)
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_revolving_work_shards.c 18 * @brief tests for the exchangedb functions whose primary table is 19 * `revolving_work_shards` 20 * @author Christian Grothoff 21 * 22 * Covers #TALER_EXCHANGEDB_begin_revolving_shard(), 23 * #TALER_EXCHANGEDB_release_revolving_shard() and, for its 24 * `revolving_work_shards` half, #TALER_EXCHANGEDB_delete_shard_locks(). 25 * 26 * Unlike `work_shards`, this table is finite: once the configured shard 27 * limit is covered, the same shards are handed out over and over, which is 28 * what the checks below pin down. No foreign keys, so no fixtures. 29 */ 30 #include "test_common.h" 31 #include "exchange-database/begin_revolving_shard.h" 32 #include "exchange-database/delete_shard_locks.h" 33 #include "exchange-database/release_revolving_shard.h" 34 35 36 /** 37 * Releasing a shard that was never claimed does nothing. 38 * 39 * @param pg the database context 40 * @return 0 on success 41 */ 42 static int 43 check_empty (struct TALER_EXCHANGEDB_PostgresContext *pg) 44 { 45 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 46 TALER_EXCHANGEDB_release_revolving_shard (pg, 47 "rws-nothing", 48 0, 49 9)); 50 FAILIF (0 != TDB_count (pg, 51 "FROM revolving_work_shards")); 52 return 0; 53 } 54 55 56 /** 57 * Fresh shards tile the range [0,shard_limit) and are handed out active. 58 * 59 * @param pg the database context 60 * @return 0 on success 61 */ 62 static int 63 check_claim_fresh (struct TALER_EXCHANGEDB_PostgresContext *pg) 64 { 65 uint32_t start; 66 uint32_t end; 67 68 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 69 TALER_EXCHANGEDB_begin_revolving_shard (pg, 70 "rws-claim", 71 10, 72 25, 73 &start, 74 &end)); 75 FAILIF (0 != start); 76 FAILIF (9 != end); 77 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 78 TALER_EXCHANGEDB_begin_revolving_shard (pg, 79 "rws-claim", 80 10, 81 25, 82 &start, 83 &end)); 84 FAILIF (10 != start); 85 FAILIF (19 != end); 86 /* the last shard is clipped to the limit */ 87 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 88 TALER_EXCHANGEDB_begin_revolving_shard (pg, 89 "rws-claim", 90 10, 91 25, 92 &start, 93 &end)); 94 FAILIF (20 != start); 95 FAILIF (25 != end); 96 FAILIF (3 != TDB_count (pg, 97 "FROM revolving_work_shards" 98 " WHERE job_name='rws-claim'" 99 " AND active")); 100 return 0; 101 } 102 103 104 /** 105 * Once the range is covered, no further shard can be claimed until one is 106 * released, and then it is that one that comes back. 107 * 108 * @param pg the database context 109 * @return 0 on success 110 */ 111 static int 112 check_exhausted_and_release (struct TALER_EXCHANGEDB_PostgresContext *pg) 113 { 114 uint32_t start; 115 uint32_t end; 116 117 /* everything from check_claim_fresh() is still active */ 118 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 119 TALER_EXCHANGEDB_begin_revolving_shard (pg, 120 "rws-claim", 121 10, 122 25, 123 &start, 124 &end)); 125 126 /* releasing a range that was never claimed changes nothing */ 127 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 128 TALER_EXCHANGEDB_release_revolving_shard (pg, 129 "rws-claim", 130 0, 131 8)); 132 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 133 TALER_EXCHANGEDB_release_revolving_shard (pg, 134 "rws-claim-elsewhere", 135 10, 136 19)); 137 138 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 139 TALER_EXCHANGEDB_release_revolving_shard (pg, 140 "rws-claim", 141 10, 142 19)); 143 FAILIF (1 != TDB_count (pg, 144 "FROM revolving_work_shards" 145 " WHERE job_name='rws-claim'" 146 " AND NOT active")); 147 /* the released shard is the only one available, so it comes back */ 148 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 149 TALER_EXCHANGEDB_begin_revolving_shard (pg, 150 "rws-claim", 151 10, 152 25, 153 &start, 154 &end)); 155 FAILIF (10 != start); 156 FAILIF (19 != end); 157 FAILIF (3 != TDB_count (pg, 158 "FROM revolving_work_shards" 159 " WHERE job_name='rws-claim'" 160 " AND active")); 161 /* releasing twice is idempotent from the caller's point of view */ 162 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 163 TALER_EXCHANGEDB_release_revolving_shard (pg, 164 "rws-claim", 165 10, 166 19)); 167 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 168 TALER_EXCHANGEDB_release_revolving_shard (pg, 169 "rws-claim", 170 10, 171 19)); 172 return 0; 173 } 174 175 176 /** 177 * A shard size at or above the limit yields a single shard covering 178 * everything. 179 * 180 * @param pg the database context 181 * @return 0 on success 182 */ 183 static int 184 check_single_shard (struct TALER_EXCHANGEDB_PostgresContext *pg) 185 { 186 uint32_t start; 187 uint32_t end; 188 189 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 190 TALER_EXCHANGEDB_begin_revolving_shard (pg, 191 "rws-single", 192 1000, 193 4, 194 &start, 195 &end)); 196 FAILIF (0 != start); 197 FAILIF (4 != end); 198 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 199 TALER_EXCHANGEDB_begin_revolving_shard (pg, 200 "rws-single", 201 1000, 202 4, 203 &start, 204 &end)); 205 return 0; 206 } 207 208 209 /** 210 * Deleting the shard locks empties the table. Runs last. 211 * 212 * @param pg the database context 213 * @return 0 on success 214 */ 215 static int 216 check_delete_locks (struct TALER_EXCHANGEDB_PostgresContext *pg) 217 { 218 uint32_t start; 219 uint32_t end; 220 221 FAILIF (0 == TDB_count (pg, 222 "FROM revolving_work_shards")); 223 FAILIF (GNUNET_OK != 224 TALER_EXCHANGEDB_delete_shard_locks (pg)); 225 FAILIF (0 != TDB_count (pg, 226 "FROM revolving_work_shards")); 227 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 228 TALER_EXCHANGEDB_begin_revolving_shard (pg, 229 "rws-claim", 230 10, 231 25, 232 &start, 233 &end)); 234 FAILIF (0 != start); 235 return 0; 236 } 237 238 239 /** 240 * The checks to run, in order. 241 */ 242 static const struct TDB_Test tests[] = { 243 { "revolving-work-shards-empty", 244 &check_empty }, 245 { "revolving-work-shards-claim-fresh", 246 &check_claim_fresh }, 247 { "revolving-work-shards-exhausted-and-release", 248 &check_exhausted_and_release }, 249 { "revolving-work-shards-single-shard", 250 &check_single_shard }, 251 { "revolving-work-shards-delete-locks", 252 &check_delete_locks }, 253 { NULL, NULL } 254 }; 255 256 257 int 258 main (int argc, 259 char *const *argv) 260 { 261 return TDB_main (argc, 262 argv, 263 "test-revolving-work-shards", 264 "Tests for the exchangedb `revolving_work_shards' table", 265 tests); 266 } 267 268 269 /* end of test_revolving_work_shards.c */