sync

Backup service to store encrypted wallet databases (experimental)
Log | Files | Refs | Submodules | README | LICENSE

test_sync_db.c (32147B)


      1 /*
      2   This file is part of TALER
      3   (C) 2019 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Lesser 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 syncdb/test_sync_db.c
     18  * @brief testcase for sync postgres db
     19  * @author Christian Grothoff
     20  */
     21 #include "platform.h"
     22 #include <gnunet/gnunet_util_lib.h>
     23 #include <taler/taler_util.h>
     24 #include "sync/sync_service.h"
     25 #include "sync/sync_database_lib.h"
     26 #include "sync/sync_util.h"
     27 
     28 
     29 #define FAILIF(cond)                            \
     30         do {                                          \
     31           if (! (cond)) { break;}                       \
     32           GNUNET_break (0);                           \
     33           goto drop;                                     \
     34         } while (0)
     35 
     36 #define RND_BLK(ptr)                                                    \
     37         GNUNET_CRYPTO_random_block (ptr, sizeof (*ptr))
     38 
     39 /**
     40  * Global return value for the test.  Initially #EXIT_FAILURE, set to
     41  * 0 upon completion.  Other values indicate some kind of error.
     42  */
     43 static int result;
     44 
     45 
     46 /**
     47  * Function called on all pending payments for an account.
     48  *
     49  * @param cls closure
     50  * @param timestamp for how long have we been waiting
     51  * @param order_id order id in the backend
     52  * @param token claim token, or NULL for none
     53  * @param amount how much is the order for
     54  */
     55 static void
     56 payment_it (void *cls,
     57             struct GNUNET_TIME_Timestamp timestamp,
     58             const char *order_id,
     59             const struct TALER_ClaimTokenP *token,
     60             const struct TALER_Amount *amount)
     61 {
     62   (void) timestamp;
     63   (void) token;
     64   (void) amount;
     65   GNUNET_assert (NULL == cls);
     66   GNUNET_assert (0 == strcmp (order_id,
     67                               "fake-order-2"));
     68 }
     69 
     70 
     71 /**
     72  * Iterator used by the #SYNCDB_lookup_block_range_TR() tests,
     73  * simply counts the blocks it is called with.
     74  *
     75  * @param cls an `int *` counter to increment
     76  * @param nonce block nonce
     77  * @param block_hash hash of the block data
     78  * @param prev_nonce previous block nonce (NULL if first)
     79  * @param next_nonce next block nonce (NULL if last)
     80  * @param data_size size of @a data
     81  * @param data encrypted block contents
     82  * @param upload_sig signature stored with the block
     83  * @param old_hash hash of the replaced block data
     84  * @param refs_hash hash over the object references
     85  */
     86 static void
     87 block_it (void *cls,
     88           const struct SYNC_BlockNonce *nonce,
     89           const struct GNUNET_HashCode *block_hash,
     90           const struct SYNC_BlockNonce *prev_nonce,
     91           const struct SYNC_BlockNonce *next_nonce,
     92           size_t data_size,
     93           const void *data,
     94           const struct SYNC_AccountSignatureP *upload_sig,
     95           const struct GNUNET_HashCode *old_hash,
     96           const struct GNUNET_HashCode *refs_hash)
     97 {
     98   (void) upload_sig;
     99   (void) old_hash;
    100   (void) refs_hash;
    101   int *cnt = cls;
    102 
    103   (void) nonce;
    104   (void) block_hash;
    105   (void) prev_nonce;
    106   (void) next_nonce;
    107   (void) data_size;
    108   (void) data;
    109   (*cnt)++;
    110 }
    111 
    112 
    113 /**
    114  * Create a paid account, so that the SQL entry points do not reject
    115  * it with #SYNC_DB_PAYMENT_REQUIRED.
    116  *
    117  * @param account_pub account to activate
    118  * @param order_id (unique) order ID to use for the fake payment
    119  * @return #GNUNET_OK on success
    120  */
    121 static enum GNUNET_GenericReturnValue
    122 activate_account (const struct SYNC_AccountPublicKeyP *account_pub,
    123                   const char *order_id)
    124 {
    125   struct TALER_Amount amount;
    126   struct TALER_ClaimTokenP token;
    127 
    128   memset (&token, 3, sizeof (token));
    129   if (GNUNET_OK !=
    130       TALER_string_to_amount ("EUR:1",
    131                               &amount))
    132   {
    133     GNUNET_break (0);
    134     return GNUNET_SYSERR;
    135   }
    136   if (SYNC_DB_ONE_RESULT !=
    137       SYNCDB_store_payment_TR (account_pub,
    138                                order_id,
    139                                &token,
    140                                &amount,
    141                                GNUNET_TIME_UNIT_MINUTES))
    142   {
    143     GNUNET_break (0);
    144     return GNUNET_SYSERR;
    145   }
    146   if (SYNC_DB_ONE_RESULT !=
    147       SYNCDB_increment_lifetime_TR (account_pub,
    148                                     order_id,
    149                                     GNUNET_TIME_UNIT_MINUTES))
    150   {
    151     GNUNET_break (0);
    152     return GNUNET_SYSERR;
    153   }
    154   return GNUNET_OK;
    155 }
    156 
    157 
    158 /**
    159  * Count the blocks currently stored for @a account_pub.
    160  *
    161  * @param account_pub account to count blocks of
    162  * @return number of blocks found
    163  */
    164 static int
    165 count_blocks (const struct SYNC_AccountPublicKeyP *account_pub)
    166 {
    167   int got = 0;
    168 
    169   SYNCDB_lookup_block_range_TR (account_pub,
    170                                 NULL,
    171                                 100,
    172                                 &block_it,
    173                                 &got);
    174   return got;
    175 }
    176 
    177 
    178 /**
    179  * Main function that will be run by the scheduler.
    180  *
    181  * @param cls closure with config
    182  */
    183 static void
    184 run (void *cls)
    185 {
    186   struct GNUNET_CONFIGURATION_Handle *cfg = cls;
    187   struct TALER_Amount amount;
    188   struct SYNC_AccountPublicKeyP account_pub;
    189   struct GNUNET_HashCode h;
    190   struct GNUNET_HashCode h2;
    191   struct GNUNET_TIME_Absolute ts;
    192   struct TALER_ClaimTokenP token;
    193   /* P1: fake signature/refs for the DB-level tests (the procedures
    194      store, they do not verify) */
    195   struct SYNC_AccountSignatureP fake_sig;
    196   struct GNUNET_HashCode empty_refs;
    197 
    198   memset (&fake_sig, 7, sizeof (fake_sig));
    199   GNUNET_CRYPTO_hash ("", 0, &empty_refs);
    200 
    201   if (GNUNET_OK !=
    202       SYNCDB_init_admin (cfg))
    203   {
    204     result = 77;
    205     return;
    206   }
    207   if (GNUNET_OK !=
    208       SYNCDB_drop_tables ())
    209   {
    210     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    211                 "Dropping tables failed\n");
    212   }
    213   if (GNUNET_OK !=
    214       SYNCDB_create_tables ())
    215   {
    216     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    217                 "Creating tables failed\n");
    218   }
    219   GNUNET_assert (GNUNET_OK ==
    220                  SYNCDB_preflight ());
    221   memset (&account_pub, 1, sizeof (account_pub));
    222   memset (&token, 3, sizeof (token));
    223   GNUNET_CRYPTO_hash ("data", 4, &h);
    224   GNUNET_CRYPTO_hash ("DATA", 4, &h2);
    225   GNUNET_assert (GNUNET_OK ==
    226                  TALER_string_to_amount ("EUR:1",
    227                                          &amount));
    228   FAILIF (SYNC_DB_ONE_RESULT !=
    229           SYNCDB_store_payment_TR (
    230             &account_pub,
    231             "fake-order",
    232             &token,
    233             &amount,
    234             GNUNET_TIME_UNIT_MINUTES));
    235   FAILIF (SYNC_DB_ONE_RESULT !=
    236           SYNCDB_increment_lifetime_TR (
    237             &account_pub,
    238             "fake-order",
    239             GNUNET_TIME_UNIT_MINUTES));
    240 
    241   FAILIF (0 !=
    242           SYNCDB_lookup_pending_payments_by_account_TR (
    243             &account_pub,
    244             &payment_it,
    245             NULL));
    246   memset (&account_pub, 2, sizeof (account_pub));
    247   FAILIF (SYNC_DB_ONE_RESULT !=
    248           SYNCDB_store_payment_TR (
    249             &account_pub,
    250             "fake-order-2",
    251             &token,
    252             &amount,
    253             GNUNET_TIME_UNIT_MINUTES));
    254   FAILIF (1 !=
    255           SYNCDB_lookup_pending_payments_by_account_TR (
    256             &account_pub,
    257             &payment_it,
    258             NULL));
    259   FAILIF (SYNC_DB_ONE_RESULT !=
    260           SYNCDB_increment_lifetime_TR (
    261             &account_pub,
    262             "fake-order-2",
    263             GNUNET_TIME_UNIT_MINUTES));
    264   /* --- DLL tests: append three blocks A->B->C and validate lookup --- */
    265   {
    266     struct SYNC_BlockNonce nA;
    267     struct SYNC_BlockNonce nB;
    268     struct SYNC_BlockNonce nC;
    269     struct GNUNET_HashCode hA;
    270     struct GNUNET_HashCode hB;
    271     struct GNUNET_HashCode hC;
    272     char dataA[] = "A";
    273     char dataB[] = "B";
    274     char dataC[] = "C";
    275     int got;
    276 
    277     RND_BLK (&nA);
    278     RND_BLK (&nB);
    279     RND_BLK (&nC);
    280     GNUNET_CRYPTO_hash (dataA, sizeof dataA - 1, &hA);
    281     GNUNET_CRYPTO_hash (dataB, sizeof dataB - 1, &hB);
    282     GNUNET_CRYPTO_hash (dataC, sizeof dataC - 1, &hC);
    283 
    284     /* Append A (prev NULL) */
    285     FAILIF (SYNC_DB_ONE_RESULT !=
    286             SYNCDB_append_block_TR (
    287               &account_pub,
    288               &nA,
    289               NULL,
    290               &hA,
    291               sizeof dataA - 1,
    292               dataA,
    293               0,
    294               NULL,
    295               NULL,
    296               &fake_sig,
    297               &empty_refs,
    298               NULL,
    299               NULL,
    300               NULL));
    301 
    302 
    303     /* Append B (prev A) */
    304     FAILIF (SYNC_DB_ONE_RESULT !=
    305             SYNCDB_append_block_TR (
    306               &account_pub,
    307               &nB,
    308               &nA,
    309               &hB,
    310               sizeof dataB - 1,
    311               dataB,
    312               0,
    313               NULL,
    314               NULL,
    315               &fake_sig,
    316               &empty_refs,
    317               &fake_sig,
    318               &hA,
    319               NULL));
    320 
    321 
    322     /* Append C (prev B) */
    323     FAILIF (SYNC_DB_ONE_RESULT !=
    324             SYNCDB_append_block_TR (
    325               &account_pub,
    326               &nC,
    327               &nB,
    328               &hC,
    329               sizeof dataC - 1,
    330               dataC,
    331               0,
    332               NULL,
    333               NULL,
    334               &fake_sig,
    335               &empty_refs,
    336               &fake_sig,
    337               &hB,
    338               &nA));
    339 
    340     /* Verify lookup returns 3 blocks */
    341     got = 0;
    342     FAILIF (3 !=
    343             SYNCDB_lookup_block_range_TR (
    344               &account_pub,
    345               &nA,
    346               10,
    347               &block_it,
    348               &got));
    349     FAILIF (got != 3);
    350 
    351     /* The relink signature covers the neighbour's other link, so an
    352        append whose view of it went stale must be refused rather than
    353        stored (the caller reads the neighbour outside the transaction) */
    354     {
    355       struct SYNC_BlockNonce nS;
    356       struct GNUNET_HashCode hS;
    357       char dataS[] = "S";
    358 
    359       RND_BLK (&nS);
    360       GNUNET_CRYPTO_hash (dataS, sizeof dataS - 1, &hS);
    361       FAILIF (SYNC_DB_OUTDATED_WRITE !=
    362               SYNCDB_append_block_TR (
    363                 &account_pub,
    364                 &nS,
    365                 &nC,
    366                 &hS,
    367                 sizeof dataS - 1,
    368                 dataS,
    369                 0,
    370                 NULL,
    371                 NULL,
    372                 &fake_sig,
    373                 &empty_refs,
    374                 &fake_sig,
    375                 &hC,
    376                 /* C's predecessor is B, not A */ &nA));
    377       FAILIF (3 != count_blocks (&account_pub));
    378     }
    379 
    380     /* Delete middle block B (use its prev and next) */
    381     FAILIF (SYNC_DB_ONE_RESULT !=
    382             SYNCDB_delete_block_TR (
    383               &account_pub,
    384               &nB,
    385               &nA,
    386               &nC,
    387               &hB,
    388               0,
    389               NULL,
    390               NULL,
    391               &fake_sig,
    392               &hA,
    393               NULL,
    394               &fake_sig,
    395               &hC,
    396               NULL));
    397 
    398     /* Update block C (test update path) */
    399     {
    400       struct GNUNET_HashCode newC;
    401       char newDataC[] = "C-new";
    402 
    403       GNUNET_CRYPTO_hash (newDataC, sizeof newDataC - 1, &newC);
    404       FAILIF (SYNC_DB_ONE_RESULT !=
    405               SYNCDB_update_block_TR (
    406                 &account_pub,
    407                 &nC,
    408                 /* prev */ &nA,
    409                 /* next */ NULL,
    410                 &hC,
    411                 &newC,
    412                 sizeof newDataC - 1,
    413                 newDataC,
    414                 0,
    415                 NULL,
    416                 NULL,
    417                 &fake_sig,
    418                 &empty_refs));
    419       hC = newC;
    420     }
    421 
    422     /* --- Outdated-write tests --- */
    423     {
    424       struct SYNC_BlockNonce nD;
    425       struct GNUNET_HashCode hD;
    426       char dataD[] = "D";
    427       struct GNUNET_HashCode bogus_old;
    428       char newDataC2[] = "C-newer";
    429       struct GNUNET_HashCode newC2;
    430 
    431       RND_BLK (&nD);
    432       GNUNET_CRYPTO_hash (dataD, sizeof dataD - 1, &hD);
    433 
    434       /* Appending with NULL prev when backup is non-empty should be outdated */
    435       FAILIF (SYNC_DB_OUTDATED_WRITE !=
    436               SYNCDB_append_block_TR (
    437                 &account_pub,
    438                 &nD,
    439                 /* prev */ NULL,
    440                 &hD,
    441                 sizeof dataD - 1,
    442                 dataD,
    443                 0,
    444                 NULL,
    445                 NULL,
    446                 &fake_sig,
    447                 &empty_refs,
    448                 NULL,
    449                 NULL,
    450                 NULL));
    451 
    452       /* Updating C with wrong old-data-hash should be outdated */
    453       GNUNET_CRYPTO_hash ("bogus", 5, &bogus_old);
    454       GNUNET_CRYPTO_hash (newDataC2, sizeof newDataC2 - 1, &newC2);
    455       FAILIF (SYNC_DB_OUTDATED_WRITE !=
    456               SYNCDB_update_block_TR (
    457                 &account_pub,
    458                 &nC,
    459                 /* prev */ &nA,
    460                 /* next */ NULL,
    461                 &bogus_old,
    462                 &newC2,
    463                 sizeof newDataC2 - 1,
    464                 newDataC2,
    465                 0,
    466                 NULL,
    467                 NULL,
    468                 &fake_sig,
    469                 &empty_refs));
    470 
    471       /* Deleting C with wrong prev nonce should be outdated */
    472       FAILIF (SYNC_DB_OUTDATED_WRITE !=
    473               SYNCDB_delete_block_TR (
    474                 &account_pub,
    475                 &nC,
    476                 /* prev (wrong) */ &nB,
    477                 /* next */ NULL,
    478                 &hC,
    479                 0,
    480                 NULL,
    481                 NULL,
    482                 NULL,
    483                 NULL,
    484                 NULL,
    485                 NULL,
    486                 NULL,
    487                 NULL));
    488     }
    489   }
    490 
    491   /* --- Account status lookup --- */
    492   {
    493     struct SYNC_AccountPublicKeyP acc;
    494     struct SYNC_BlockNonce nonce;
    495     struct GNUNET_HashCode bh;
    496     char data[] = "account-status-block";
    497     struct GNUNET_TIME_Timestamp expiration;
    498     uint64_t storage_used_bytes;
    499     uint64_t block_count;
    500 
    501     memset (&acc, 20, sizeof (acc));
    502 
    503     /* An account nobody has heard of is missing, not expired */
    504     FAILIF (SYNC_DB_TARGET_MISSING !=
    505             SYNCDB_lookup_account_TR (&acc,
    506                                       &expiration,
    507                                       &storage_used_bytes,
    508                                       &block_count));
    509 
    510     FAILIF (GNUNET_OK !=
    511             activate_account (&acc,
    512                               "fake-order-account-status"));
    513 
    514     /* A fresh account has an expiration and no storage in use */
    515     FAILIF (SYNC_DB_ONE_RESULT !=
    516             SYNCDB_lookup_account_TR (&acc,
    517                                       &expiration,
    518                                       &storage_used_bytes,
    519                                       &block_count));
    520     FAILIF (GNUNET_TIME_absolute_is_zero (expiration.abs_time));
    521     FAILIF (0 != storage_used_bytes);
    522     FAILIF (0 != block_count);
    523 
    524     /* ... and the block it stores is reflected in both counters */
    525     RND_BLK (&nonce);
    526     GNUNET_CRYPTO_hash (data, sizeof data - 1, &bh);
    527     FAILIF (SYNC_DB_ONE_RESULT !=
    528             SYNCDB_append_block_TR (&acc,
    529                                     &nonce,
    530                                     NULL,
    531                                     &bh,
    532                                     sizeof data - 1,
    533                                     data,
    534                                     0,
    535                                     NULL,
    536                                     NULL,
    537                                     &fake_sig,
    538                                     &empty_refs,
    539                                     NULL,
    540                                     NULL,
    541                                     NULL));
    542     FAILIF (SYNC_DB_ONE_RESULT !=
    543             SYNCDB_lookup_account_TR (&acc,
    544                                       &expiration,
    545                                       &storage_used_bytes,
    546                                       &block_count));
    547     FAILIF (sizeof data - 1 != storage_used_bytes);
    548     FAILIF (1 != block_count);
    549 
    550     /* The blocks of other accounts must not be counted here */
    551     FAILIF (SYNC_DB_ONE_RESULT !=
    552             SYNCDB_lookup_account_TR (&account_pub,
    553                                       &expiration,
    554                                       &storage_used_bytes,
    555                                       &block_count));
    556     FAILIF (1 == block_count);
    557   }
    558 
    559   /* --- Object store/lookup tests --- */
    560   {
    561     struct SYNC_ObjectUID obj_uid;
    562     struct GNUNET_HashCode obj_hash;
    563     char obj_data[] = "objdata";
    564     int64_t refcount = 0;
    565     struct GNUNET_TIME_Timestamp exp;
    566     size_t data_sz = 0;
    567 
    568     RND_BLK (&obj_uid);
    569     GNUNET_CRYPTO_hash (obj_data, sizeof obj_data - 1, &obj_hash);
    570     FAILIF (SYNC_DB_ONE_RESULT !=
    571             SYNCDB_store_object_TR (
    572               &obj_uid,
    573               &account_pub,
    574               &obj_hash,
    575               GNUNET_TIME_UNIT_DAYS,
    576               sizeof obj_data - 1,
    577               obj_data));
    578 
    579     FAILIF (SYNC_DB_ONE_RESULT !=
    580             SYNCDB_lookup_object (
    581               &account_pub,
    582               &obj_hash,
    583               &refcount,
    584               &exp,
    585               &data_sz,
    586               NULL));
    587     FAILIF (refcount < 0);
    588 
    589     /* A missing object is a normal outcome, not a failure */
    590     {
    591       struct GNUNET_HashCode bogus_hash;
    592 
    593       GNUNET_CRYPTO_hash ("no-such-object",
    594                           14,
    595                           &bogus_hash);
    596       FAILIF (SYNC_DB_NO_RESULTS !=
    597               SYNCDB_lookup_object (&account_pub,
    598                                     &bogus_hash,
    599                                     &refcount,
    600                                     &exp,
    601                                     &data_sz,
    602                                     NULL));
    603     }
    604   }
    605 
    606   /* --- Referencing an object that was never uploaded --- */
    607   {
    608     struct SYNC_AccountPublicKeyP acc;
    609     struct SYNC_BlockNonce nonce;
    610     struct GNUNET_HashCode bh;
    611     struct SYNC_ObjectUID unknown_uid;
    612     const int16_t inc = 1;
    613     char data[] = "orphan";
    614 
    615     memset (&acc, 10, sizeof (acc));
    616     FAILIF (GNUNET_OK !=
    617             activate_account (&acc,
    618                               "fake-order-refs-missing"));
    619     RND_BLK (&nonce);
    620     RND_BLK (&unknown_uid);
    621     GNUNET_CRYPTO_hash (data, sizeof data - 1, &bh);
    622     FAILIF (SYNC_DB_INCONSISTENT_BACKUP !=
    623             SYNCDB_append_block_TR (&acc,
    624                                     &nonce,
    625                                     NULL,
    626                                     &bh,
    627                                     sizeof data - 1,
    628                                     data,
    629                                     1,
    630                                     &unknown_uid,
    631                                     &inc,
    632                                     &fake_sig,
    633                                     &empty_refs,
    634                                     NULL,
    635                                     NULL,
    636                                     NULL));
    637     /* the rejected append must be a no-op */
    638     FAILIF (0 != count_blocks (&acc));
    639   }
    640 
    641   /* --- A nonce that is already taken is a conflict --- */
    642   {
    643     struct SYNC_AccountPublicKeyP acc_a;
    644     struct SYNC_AccountPublicKeyP acc_b;
    645     struct SYNC_BlockNonce nonce;
    646     struct GNUNET_HashCode bh;
    647     char data[] = "shared-nonce";
    648 
    649     memset (&acc_a, 11, sizeof (acc_a));
    650     memset (&acc_b, 12, sizeof (acc_b));
    651     FAILIF (GNUNET_OK !=
    652             activate_account (&acc_a,
    653                               "fake-order-nonce-a"));
    654     FAILIF (GNUNET_OK !=
    655             activate_account (&acc_b,
    656                               "fake-order-nonce-b"));
    657     RND_BLK (&nonce);
    658     GNUNET_CRYPTO_hash (data, sizeof data - 1, &bh);
    659     FAILIF (SYNC_DB_ONE_RESULT !=
    660             SYNCDB_append_block_TR (&acc_a,
    661                                     &nonce,
    662                                     NULL,
    663                                     &bh,
    664                                     sizeof data - 1,
    665                                     data,
    666                                     0,
    667                                     NULL,
    668                                     NULL,
    669                                     &fake_sig,
    670                                     &empty_refs,
    671                                     NULL,
    672                                     NULL,
    673                                     NULL));
    674     FAILIF (SYNC_DB_OUTDATED_WRITE !=
    675             SYNCDB_append_block_TR (&acc_b,
    676                                     &nonce,
    677                                     NULL,
    678                                     &bh,
    679                                     sizeof data - 1,
    680                                     data,
    681                                     0,
    682                                     NULL,
    683                                     NULL,
    684                                     &fake_sig,
    685                                     &empty_refs,
    686                                     NULL,
    687                                     NULL,
    688                                     NULL));
    689     /* the rejected append must not have touched account B */
    690     FAILIF (0 != count_blocks (&acc_b));
    691   }
    692 
    693   /* --- Refcount lifecycle --- */
    694   {
    695     struct SYNC_AccountPublicKeyP acc;
    696     struct SYNC_BlockNonce nonce;
    697     struct GNUNET_HashCode bh;
    698     struct SYNC_ObjectUID uid;
    699     struct GNUNET_HashCode oh;
    700     const int16_t inc = 1;
    701     const int16_t dec = -1;
    702     const int16_t dec2 = -2;
    703     char data[] = "refcounted";
    704     char obj[] = "payload";
    705     int64_t refcount = 0;
    706     struct GNUNET_TIME_Timestamp exp;
    707     size_t data_sz = 0;
    708 
    709     memset (&acc, 13, sizeof (acc));
    710     FAILIF (GNUNET_OK !=
    711             activate_account (&acc,
    712                               "fake-order-refcount"));
    713     RND_BLK (&nonce);
    714     RND_BLK (&uid);
    715     GNUNET_CRYPTO_hash (data, sizeof data - 1, &bh);
    716     GNUNET_CRYPTO_hash (obj, sizeof obj - 1, &oh);
    717     FAILIF (SYNC_DB_ONE_RESULT !=
    718             SYNCDB_store_object_TR (&uid,
    719                                     &acc,
    720                                     &oh,
    721                                     GNUNET_TIME_UNIT_DAYS,
    722                                     sizeof obj - 1,
    723                                     obj));
    724     /* re-uploading the same UID is idempotent, not an error */
    725     FAILIF (SYNC_DB_ONE_RESULT !=
    726             SYNCDB_store_object_TR (&uid,
    727                                     &acc,
    728                                     &oh,
    729                                     GNUNET_TIME_UNIT_DAYS,
    730                                     sizeof obj - 1,
    731                                     obj));
    732     FAILIF (SYNC_DB_ONE_RESULT !=
    733             SYNCDB_append_block_TR (&acc,
    734                                     &nonce,
    735                                     NULL,
    736                                     &bh,
    737                                     sizeof data - 1,
    738                                     data,
    739                                     1,
    740                                     &uid,
    741                                     &inc,
    742                                     &fake_sig,
    743                                     &empty_refs,
    744                                     NULL,
    745                                     NULL,
    746                                     NULL));
    747     FAILIF (SYNC_DB_ONE_RESULT !=
    748             SYNCDB_lookup_object (&acc,
    749                                   &oh,
    750                                   &refcount,
    751                                   &exp,
    752                                   &data_sz,
    753                                   NULL));
    754     FAILIF (1 != refcount);
    755 
    756     /* decrementing below zero is refused, refcount untouched */
    757     FAILIF (SYNC_DB_INCONSISTENT_BACKUP !=
    758             SYNCDB_delete_block_TR (&acc,
    759                                     &nonce,
    760                                     NULL,
    761                                     NULL,
    762                                     &bh,
    763                                     1,
    764                                     &uid,
    765                                     &dec2,
    766                                     NULL,
    767                                     NULL,
    768                                     NULL,
    769                                     NULL,
    770                                     NULL,
    771                                     NULL));
    772     FAILIF (SYNC_DB_ONE_RESULT !=
    773             SYNCDB_lookup_object (&acc,
    774                                   &oh,
    775                                   &refcount,
    776                                   &exp,
    777                                   &data_sz,
    778                                   NULL));
    779     FAILIF (1 != refcount);
    780     /* ... and the block must still be there */
    781     FAILIF (1 != count_blocks (&acc));
    782 
    783     /* the matching decrement drops it to 0, deleting the object */
    784     FAILIF (SYNC_DB_ONE_RESULT !=
    785             SYNCDB_delete_block_TR (&acc,
    786                                     &nonce,
    787                                     NULL,
    788                                     NULL,
    789                                     &bh,
    790                                     1,
    791                                     &uid,
    792                                     &dec,
    793                                     NULL,
    794                                     NULL,
    795                                     NULL,
    796                                     NULL,
    797                                     NULL,
    798                                     NULL));
    799     FAILIF (SYNC_DB_NO_RESULTS !=
    800             SYNCDB_lookup_object (&acc,
    801                                   &oh,
    802                                   &refcount,
    803                                   &exp,
    804                                   &data_sz,
    805                                   NULL));
    806     FAILIF (0 != count_blocks (&acc));
    807   }
    808 
    809   /* --- Increments for the same UID are aggregated --- */
    810   {
    811     struct SYNC_AccountPublicKeyP acc;
    812     struct SYNC_BlockNonce nonce;
    813     struct GNUNET_HashCode bh;
    814     struct SYNC_ObjectUID uids[2];
    815     struct GNUNET_HashCode oh;
    816     const int16_t incs[2] = { -1, 1 };
    817     char data[] = "net-zero";
    818     char obj[] = "aggregated";
    819     int64_t refcount = 0;
    820     struct GNUNET_TIME_Timestamp exp;
    821     size_t data_sz = 0;
    822 
    823     memset (&acc, 14, sizeof (acc));
    824     FAILIF (GNUNET_OK !=
    825             activate_account (&acc,
    826                               "fake-order-aggregate"));
    827     RND_BLK (&nonce);
    828     RND_BLK (&uids[0]);
    829     uids[1] = uids[0];
    830     GNUNET_CRYPTO_hash (data, sizeof data - 1, &bh);
    831     GNUNET_CRYPTO_hash (obj, sizeof obj - 1, &oh);
    832     FAILIF (SYNC_DB_ONE_RESULT !=
    833             SYNCDB_store_object_TR (&uids[0],
    834                                     &acc,
    835                                     &oh,
    836                                     GNUNET_TIME_UNIT_DAYS,
    837                                     sizeof obj - 1,
    838                                     obj));
    839     FAILIF (SYNC_DB_ONE_RESULT !=
    840             SYNCDB_append_block_TR (&acc,
    841                                     &nonce,
    842                                     NULL,
    843                                     &bh,
    844                                     sizeof data - 1,
    845                                     data,
    846                                     2,
    847                                     uids,
    848                                     incs,
    849                                     &fake_sig,
    850                                     &empty_refs,
    851                                     NULL,
    852                                     NULL,
    853                                     NULL));
    854     /* refcount unchanged, and the object still exists */
    855     FAILIF (SYNC_DB_ONE_RESULT !=
    856             SYNCDB_lookup_object (&acc,
    857                                   &oh,
    858                                   &refcount,
    859                                   &exp,
    860                                   &data_sz,
    861                                   NULL));
    862     FAILIF (0 != refcount);
    863   }
    864 
    865   /* --- GC must not remove still-referenced objects --- */
    866   {
    867     struct SYNC_AccountPublicKeyP acc;
    868     struct SYNC_BlockNonce nonce;
    869     struct GNUNET_HashCode bh;
    870     struct SYNC_ObjectUID kept_uid;
    871     struct SYNC_ObjectUID swept_uid;
    872     struct GNUNET_HashCode kept_oh;
    873     struct GNUNET_HashCode swept_oh;
    874     const int16_t inc = 1;
    875     char data[] = "gc-block";
    876     char kept[] = "still-referenced";
    877     char swept[] = "unreferenced";
    878     int64_t refcount = 0;
    879     struct GNUNET_TIME_Timestamp exp;
    880     size_t data_sz = 0;
    881     struct GNUNET_TIME_Absolute future;
    882 
    883     memset (&acc, 15, sizeof (acc));
    884     FAILIF (GNUNET_OK !=
    885             activate_account (&acc,
    886                               "fake-order-gc"));
    887     RND_BLK (&nonce);
    888     RND_BLK (&kept_uid);
    889     RND_BLK (&swept_uid);
    890     GNUNET_CRYPTO_hash (data, sizeof data - 1, &bh);
    891     GNUNET_CRYPTO_hash (kept, sizeof kept - 1, &kept_oh);
    892     GNUNET_CRYPTO_hash (swept, sizeof swept - 1, &swept_oh);
    893     FAILIF (SYNC_DB_ONE_RESULT !=
    894             SYNCDB_store_object_TR (&kept_uid,
    895                                     &acc,
    896                                     &kept_oh,
    897                                     GNUNET_TIME_UNIT_DAYS,
    898                                     sizeof kept - 1,
    899                                     kept));
    900     FAILIF (SYNC_DB_ONE_RESULT !=
    901             SYNCDB_store_object_TR (&swept_uid,
    902                                     &acc,
    903                                     &swept_oh,
    904                                     GNUNET_TIME_UNIT_DAYS,
    905                                     sizeof swept - 1,
    906                                     swept));
    907     FAILIF (SYNC_DB_ONE_RESULT !=
    908             SYNCDB_append_block_TR (&acc,
    909                                     &nonce,
    910                                     NULL,
    911                                     &bh,
    912                                     sizeof data - 1,
    913                                     data,
    914                                     1,
    915                                     &kept_uid,
    916                                     &inc,
    917                                     &fake_sig,
    918                                     &empty_refs,
    919                                     NULL,
    920                                     NULL,
    921                                     NULL));
    922     /* Leave accounts and payments alone, only sweep objects */
    923     future = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_YEARS);
    924     FAILIF (GNUNET_OK !=
    925             SYNCDB_gc (GNUNET_TIME_UNIT_ZERO_ABS,
    926                        GNUNET_TIME_UNIT_ZERO_ABS,
    927                        future));
    928     /* the referenced object survives ... */
    929     FAILIF (SYNC_DB_ONE_RESULT !=
    930             SYNCDB_lookup_object (&acc,
    931                                   &kept_oh,
    932                                   &refcount,
    933                                   &exp,
    934                                   &data_sz,
    935                                   NULL));
    936     FAILIF (1 != refcount);
    937     /* ... the unreferenced one is collected */
    938     FAILIF (SYNC_DB_NO_RESULTS !=
    939             SYNCDB_lookup_object (&acc,
    940                                   &swept_oh,
    941                                   &refcount,
    942                                   &exp,
    943                                   &data_sz,
    944                                   NULL));
    945   }
    946 
    947   ts = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_YEARS);
    948   FAILIF (GNUNET_OK !=
    949           SYNCDB_gc (ts,
    950                      ts,
    951                      ts));
    952   result = 0;
    953 drop:
    954   GNUNET_break (GNUNET_OK ==
    955                 SYNCDB_drop_tables ());
    956   SYNCDB_fini ();
    957 }
    958 
    959 
    960 int
    961 main (int argc,
    962       char *const argv[])
    963 {
    964   const char *plugin_name;
    965   char *config_filename;
    966   struct GNUNET_CONFIGURATION_Handle *cfg;
    967 
    968   (void) argc;
    969   result = EXIT_FAILURE;
    970   /* the database backend is the suffix of our own binary name */
    971   if (NULL == (plugin_name = strrchr (argv[0], (int) '-')))
    972   {
    973     GNUNET_break (0);
    974     return EXIT_FAILURE;
    975   }
    976   plugin_name++;
    977   GNUNET_log_setup (argv[0],
    978                     "DEBUG",
    979                     NULL);
    980   GNUNET_asprintf (&config_filename,
    981                    "test_sync_db_%s.conf",
    982                    plugin_name);
    983   cfg = GNUNET_CONFIGURATION_create (SYNC_project_data ());
    984   if (GNUNET_OK !=
    985       GNUNET_CONFIGURATION_parse (cfg,
    986                                   config_filename))
    987   {
    988     GNUNET_break (0);
    989     GNUNET_CONFIGURATION_destroy (cfg);
    990     GNUNET_free (config_filename);
    991     return EXIT_NOTCONFIGURED;
    992   }
    993   GNUNET_SCHEDULER_run (&run, cfg);
    994   GNUNET_CONFIGURATION_destroy (cfg);
    995   GNUNET_free (config_filename);
    996   return result;
    997 }
    998 
    999 
   1000 /* end of test_sync_db.c */