exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

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 */