sync

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

test_sync_db.c (36229B)


      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  * Iterator used by the #SYNCDB_lookup_block_hashes_TR() tests,
    115  * collecting the block identities it is called with.
    116  */
    117 struct HashCollector
    118 {
    119   /**
    120    * Nonces collected so far.
    121    */
    122   struct SYNC_BlockNonce nonces[8];
    123 
    124   /**
    125    * Hashes collected so far.
    126    */
    127   struct GNUNET_HashCode hashes[8];
    128 
    129   /**
    130    * Number of entries collected.
    131    */
    132   unsigned int count;
    133 };
    134 
    135 
    136 /**
    137  * Collect the block identities the iterator is called with.
    138  *
    139  * @param cls a `struct HashCollector *`
    140  * @param nonce nonce identifying the block
    141  * @param block_hash hash of the block data
    142  */
    143 static void
    144 hash_it (void *cls,
    145          const struct SYNC_BlockNonce *nonce,
    146          const struct GNUNET_HashCode *block_hash)
    147 {
    148   struct HashCollector *hc = cls;
    149 
    150   GNUNET_assert (hc->count < 8);
    151   hc->nonces[hc->count] = *nonce;
    152   hc->hashes[hc->count] = *block_hash;
    153   hc->count++;
    154 }
    155 
    156 
    157 /**
    158  * Create a paid account, so that the SQL entry points do not reject
    159  * it with #SYNC_DB_PAYMENT_REQUIRED.
    160  *
    161  * @param account_pub account to activate
    162  * @param order_id (unique) order ID to use for the fake payment
    163  * @return #GNUNET_OK on success
    164  */
    165 static enum GNUNET_GenericReturnValue
    166 activate_account (const struct SYNC_AccountPublicKeyP *account_pub,
    167                   const char *order_id)
    168 {
    169   struct TALER_Amount amount;
    170   struct TALER_ClaimTokenP token;
    171 
    172   memset (&token, 3, sizeof (token));
    173   if (GNUNET_OK !=
    174       TALER_string_to_amount ("EUR:1",
    175                               &amount))
    176   {
    177     GNUNET_break (0);
    178     return GNUNET_SYSERR;
    179   }
    180   if (SYNC_DB_ONE_RESULT !=
    181       SYNCDB_store_payment_TR (account_pub,
    182                                order_id,
    183                                &token,
    184                                &amount,
    185                                GNUNET_TIME_UNIT_MINUTES))
    186   {
    187     GNUNET_break (0);
    188     return GNUNET_SYSERR;
    189   }
    190   if (SYNC_DB_ONE_RESULT !=
    191       SYNCDB_increment_lifetime_TR (account_pub,
    192                                     order_id,
    193                                     GNUNET_TIME_UNIT_MINUTES))
    194   {
    195     GNUNET_break (0);
    196     return GNUNET_SYSERR;
    197   }
    198   return GNUNET_OK;
    199 }
    200 
    201 
    202 /**
    203  * Count the blocks currently stored for @a account_pub.
    204  *
    205  * @param account_pub account to count blocks of
    206  * @return number of blocks found
    207  */
    208 static int
    209 count_blocks (const struct SYNC_AccountPublicKeyP *account_pub)
    210 {
    211   int got = 0;
    212 
    213   SYNCDB_lookup_block_range_TR (account_pub,
    214                                 NULL,
    215                                 100,
    216                                 &block_it,
    217                                 &got);
    218   return got;
    219 }
    220 
    221 
    222 /**
    223  * Main function that will be run by the scheduler.
    224  *
    225  * @param cls closure with config
    226  */
    227 static void
    228 run (void *cls)
    229 {
    230   struct GNUNET_CONFIGURATION_Handle *cfg = cls;
    231   struct TALER_Amount amount;
    232   struct SYNC_AccountPublicKeyP account_pub;
    233   struct GNUNET_HashCode h;
    234   struct GNUNET_HashCode h2;
    235   struct GNUNET_TIME_Absolute ts;
    236   struct TALER_ClaimTokenP token;
    237   /* P1: fake signature/refs for the DB-level tests (the procedures
    238      store, they do not verify) */
    239   struct SYNC_AccountSignatureP fake_sig;
    240   struct GNUNET_HashCode empty_refs;
    241 
    242   memset (&fake_sig, 7, sizeof (fake_sig));
    243   GNUNET_CRYPTO_hash ("", 0, &empty_refs);
    244 
    245   if (GNUNET_OK !=
    246       SYNCDB_init_admin (cfg))
    247   {
    248     result = 77;
    249     return;
    250   }
    251   if (GNUNET_OK !=
    252       SYNCDB_drop_tables ())
    253   {
    254     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    255                 "Dropping tables failed\n");
    256   }
    257   if (GNUNET_OK !=
    258       SYNCDB_create_tables ())
    259   {
    260     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    261                 "Creating tables failed\n");
    262   }
    263   GNUNET_assert (GNUNET_OK ==
    264                  SYNCDB_preflight ());
    265   memset (&account_pub, 1, sizeof (account_pub));
    266   memset (&token, 3, sizeof (token));
    267   GNUNET_CRYPTO_hash ("data", 4, &h);
    268   GNUNET_CRYPTO_hash ("DATA", 4, &h2);
    269   GNUNET_assert (GNUNET_OK ==
    270                  TALER_string_to_amount ("EUR:1",
    271                                          &amount));
    272   FAILIF (SYNC_DB_ONE_RESULT !=
    273           SYNCDB_store_payment_TR (
    274             &account_pub,
    275             "fake-order",
    276             &token,
    277             &amount,
    278             GNUNET_TIME_UNIT_MINUTES));
    279   FAILIF (SYNC_DB_ONE_RESULT !=
    280           SYNCDB_increment_lifetime_TR (
    281             &account_pub,
    282             "fake-order",
    283             GNUNET_TIME_UNIT_MINUTES));
    284 
    285   FAILIF (0 !=
    286           SYNCDB_lookup_pending_payments_by_account_TR (
    287             &account_pub,
    288             &payment_it,
    289             NULL));
    290   memset (&account_pub, 2, sizeof (account_pub));
    291   FAILIF (SYNC_DB_ONE_RESULT !=
    292           SYNCDB_store_payment_TR (
    293             &account_pub,
    294             "fake-order-2",
    295             &token,
    296             &amount,
    297             GNUNET_TIME_UNIT_MINUTES));
    298   FAILIF (1 !=
    299           SYNCDB_lookup_pending_payments_by_account_TR (
    300             &account_pub,
    301             &payment_it,
    302             NULL));
    303   FAILIF (SYNC_DB_ONE_RESULT !=
    304           SYNCDB_increment_lifetime_TR (
    305             &account_pub,
    306             "fake-order-2",
    307             GNUNET_TIME_UNIT_MINUTES));
    308   /* --- DLL tests: append three blocks A->B->C and validate lookup --- */
    309   {
    310     struct SYNC_BlockNonce nA;
    311     struct SYNC_BlockNonce nB;
    312     struct SYNC_BlockNonce nC;
    313     struct GNUNET_HashCode hA;
    314     struct GNUNET_HashCode hB;
    315     struct GNUNET_HashCode hC;
    316     char dataA[] = "A";
    317     char dataB[] = "B";
    318     char dataC[] = "C";
    319     int got;
    320 
    321     RND_BLK (&nA);
    322     RND_BLK (&nB);
    323     RND_BLK (&nC);
    324     GNUNET_CRYPTO_hash (dataA, sizeof dataA - 1, &hA);
    325     GNUNET_CRYPTO_hash (dataB, sizeof dataB - 1, &hB);
    326     GNUNET_CRYPTO_hash (dataC, sizeof dataC - 1, &hC);
    327 
    328     /* Append A (prev NULL) */
    329     FAILIF (SYNC_DB_ONE_RESULT !=
    330             SYNCDB_append_block_TR (
    331               &account_pub,
    332               &nA,
    333               NULL,
    334               &hA,
    335               sizeof dataA - 1,
    336               dataA,
    337               0,
    338               NULL,
    339               NULL,
    340               &fake_sig,
    341               &empty_refs,
    342               NULL,
    343               NULL,
    344               NULL));
    345 
    346 
    347     /* Append B (prev A) */
    348     FAILIF (SYNC_DB_ONE_RESULT !=
    349             SYNCDB_append_block_TR (
    350               &account_pub,
    351               &nB,
    352               &nA,
    353               &hB,
    354               sizeof dataB - 1,
    355               dataB,
    356               0,
    357               NULL,
    358               NULL,
    359               &fake_sig,
    360               &empty_refs,
    361               &fake_sig,
    362               &hA,
    363               NULL));
    364 
    365 
    366     /* Append C (prev B) */
    367     FAILIF (SYNC_DB_ONE_RESULT !=
    368             SYNCDB_append_block_TR (
    369               &account_pub,
    370               &nC,
    371               &nB,
    372               &hC,
    373               sizeof dataC - 1,
    374               dataC,
    375               0,
    376               NULL,
    377               NULL,
    378               &fake_sig,
    379               &empty_refs,
    380               &fake_sig,
    381               &hB,
    382               &nA));
    383 
    384     /* Verify lookup returns 3 blocks */
    385     got = 0;
    386     FAILIF (3 !=
    387             SYNCDB_lookup_block_range_TR (
    388               &account_pub,
    389               &nA,
    390               10,
    391               &block_it,
    392               &got));
    393     FAILIF (got != 3);
    394 
    395     /* The relink signature covers the neighbour's other link, so an
    396        append whose view of it went stale must be refused rather than
    397        stored (the caller reads the neighbour outside the transaction) */
    398     {
    399       struct SYNC_BlockNonce nS;
    400       struct GNUNET_HashCode hS;
    401       char dataS[] = "S";
    402 
    403       RND_BLK (&nS);
    404       GNUNET_CRYPTO_hash (dataS, sizeof dataS - 1, &hS);
    405       FAILIF (SYNC_DB_OUTDATED_WRITE !=
    406               SYNCDB_append_block_TR (
    407                 &account_pub,
    408                 &nS,
    409                 &nC,
    410                 &hS,
    411                 sizeof dataS - 1,
    412                 dataS,
    413                 0,
    414                 NULL,
    415                 NULL,
    416                 &fake_sig,
    417                 &empty_refs,
    418                 &fake_sig,
    419                 &hC,
    420                 /* C's predecessor is B, not A */ &nA));
    421       FAILIF (3 != count_blocks (&account_pub));
    422     }
    423 
    424     /* Delete middle block B (use its prev and next) */
    425     FAILIF (SYNC_DB_ONE_RESULT !=
    426             SYNCDB_delete_block_TR (
    427               &account_pub,
    428               &nB,
    429               &nA,
    430               &nC,
    431               &hB,
    432               0,
    433               NULL,
    434               NULL,
    435               &fake_sig,
    436               &hA,
    437               NULL,
    438               &fake_sig,
    439               &hC,
    440               NULL));
    441 
    442     /* Update block C (test update path) */
    443     {
    444       struct GNUNET_HashCode newC;
    445       char newDataC[] = "C-new";
    446 
    447       GNUNET_CRYPTO_hash (newDataC, sizeof newDataC - 1, &newC);
    448       FAILIF (SYNC_DB_ONE_RESULT !=
    449               SYNCDB_update_block_TR (
    450                 &account_pub,
    451                 &nC,
    452                 /* prev */ &nA,
    453                 /* next */ NULL,
    454                 &hC,
    455                 &newC,
    456                 sizeof newDataC - 1,
    457                 newDataC,
    458                 0,
    459                 NULL,
    460                 NULL,
    461                 &fake_sig,
    462                 &empty_refs));
    463       hC = newC;
    464     }
    465 
    466     /* --- Outdated-write tests --- */
    467     {
    468       struct SYNC_BlockNonce nD;
    469       struct GNUNET_HashCode hD;
    470       char dataD[] = "D";
    471       struct GNUNET_HashCode bogus_old;
    472       char newDataC2[] = "C-newer";
    473       struct GNUNET_HashCode newC2;
    474 
    475       RND_BLK (&nD);
    476       GNUNET_CRYPTO_hash (dataD, sizeof dataD - 1, &hD);
    477 
    478       /* Appending with NULL prev when backup is non-empty should be outdated */
    479       FAILIF (SYNC_DB_OUTDATED_WRITE !=
    480               SYNCDB_append_block_TR (
    481                 &account_pub,
    482                 &nD,
    483                 /* prev */ NULL,
    484                 &hD,
    485                 sizeof dataD - 1,
    486                 dataD,
    487                 0,
    488                 NULL,
    489                 NULL,
    490                 &fake_sig,
    491                 &empty_refs,
    492                 NULL,
    493                 NULL,
    494                 NULL));
    495 
    496       /* Updating C with wrong old-data-hash should be outdated */
    497       GNUNET_CRYPTO_hash ("bogus", 5, &bogus_old);
    498       GNUNET_CRYPTO_hash (newDataC2, sizeof newDataC2 - 1, &newC2);
    499       FAILIF (SYNC_DB_OUTDATED_WRITE !=
    500               SYNCDB_update_block_TR (
    501                 &account_pub,
    502                 &nC,
    503                 /* prev */ &nA,
    504                 /* next */ NULL,
    505                 &bogus_old,
    506                 &newC2,
    507                 sizeof newDataC2 - 1,
    508                 newDataC2,
    509                 0,
    510                 NULL,
    511                 NULL,
    512                 &fake_sig,
    513                 &empty_refs));
    514 
    515       /* Deleting C with wrong prev nonce should be outdated */
    516       FAILIF (SYNC_DB_OUTDATED_WRITE !=
    517               SYNCDB_delete_block_TR (
    518                 &account_pub,
    519                 &nC,
    520                 /* prev (wrong) */ &nB,
    521                 /* next */ NULL,
    522                 &hC,
    523                 0,
    524                 NULL,
    525                 NULL,
    526                 NULL,
    527                 NULL,
    528                 NULL,
    529                 NULL,
    530                 NULL,
    531                 NULL));
    532     }
    533 
    534     /* --- Block hash lookup (reconcile) tests --- */
    535     {
    536       struct SYNC_AccountPublicKeyP unknown;
    537       struct SYNC_AccountPublicKeyP lone;
    538       struct SYNC_BlockNonce lone_nonce;
    539       struct GNUNET_HashCode lone_hash;
    540       char lone_data[] = "lone-block";
    541       struct HashCollector hc;
    542 
    543       /* An account nobody has heard of demands payment */
    544       memset (&unknown, 9, sizeof (unknown));
    545       FAILIF (SYNC_DB_PAYMENT_REQUIRED !=
    546               SYNCDB_lookup_block_hashes_TR (&unknown,
    547                                              NULL,
    548                                              NULL));
    549 
    550       /* A fresh, paid account with a single block delivers exactly
    551          that block's hash */
    552       memset (&lone, 16, sizeof (lone));
    553       FAILIF (GNUNET_OK !=
    554               activate_account (&lone,
    555                                 "fake-order-hashes-lone"));
    556       RND_BLK (&lone_nonce);
    557       GNUNET_CRYPTO_hash (lone_data,
    558                           sizeof lone_data - 1,
    559                           &lone_hash);
    560       FAILIF (SYNC_DB_ONE_RESULT !=
    561               SYNCDB_append_block_TR (&lone,
    562                                       &lone_nonce,
    563                                       NULL,
    564                                       &lone_hash,
    565                                       sizeof lone_data - 1,
    566                                       lone_data,
    567                                       0,
    568                                       NULL,
    569                                       NULL,
    570                                       &fake_sig,
    571                                       &empty_refs,
    572                                       NULL,
    573                                       NULL,
    574                                       NULL));
    575       memset (&hc, 0, sizeof (hc));
    576       FAILIF (1 !=
    577               SYNCDB_lookup_block_hashes_TR (&lone,
    578                                              &hash_it,
    579                                              &hc));
    580       FAILIF (1 != hc.count);
    581       FAILIF (0 != GNUNET_memcmp (&hc.hashes[0],
    582                                   &lone_hash));
    583       FAILIF (0 != GNUNET_memcmp (&hc.nonces[0],
    584                                   &lone_nonce));
    585 
    586       /* Counting pass with a NULL iterator */
    587       FAILIF (1 !=
    588               SYNCDB_lookup_block_hashes_TR (&lone,
    589                                              NULL,
    590                                              NULL));
    591 
    592       /* The DLL account now holds blocks A and C (B was deleted, C
    593          was updated), whose identities must both be delivered */
    594       memset (&hc, 0, sizeof (hc));
    595       FAILIF (2 !=
    596               SYNCDB_lookup_block_hashes_TR (&account_pub,
    597                                              &hash_it,
    598                                              &hc));
    599       FAILIF (2 != hc.count);
    600       {
    601         bool have_a = false;
    602         bool have_c = false;
    603 
    604         for (unsigned int i = 0; i < hc.count; i++)
    605         {
    606           if (0 == GNUNET_memcmp (&hc.hashes[i],
    607                                   &hA))
    608             have_a = true;
    609           if (0 == GNUNET_memcmp (&hc.hashes[i],
    610                                   &hC))
    611             have_c = true;
    612         }
    613         FAILIF (! have_a);
    614         FAILIF (! have_c);
    615       }
    616     }
    617   }
    618 
    619   /* --- Account status lookup --- */
    620   {
    621     struct SYNC_AccountPublicKeyP acc;
    622     struct SYNC_BlockNonce nonce;
    623     struct GNUNET_HashCode bh;
    624     char data[] = "account-status-block";
    625     struct GNUNET_TIME_Timestamp expiration;
    626     uint64_t storage_used_bytes;
    627     uint64_t block_count;
    628 
    629     memset (&acc, 20, sizeof (acc));
    630 
    631     /* An account nobody has heard of is missing, not expired */
    632     FAILIF (SYNC_DB_TARGET_MISSING !=
    633             SYNCDB_lookup_account_TR (&acc,
    634                                       &expiration,
    635                                       &storage_used_bytes,
    636                                       &block_count));
    637 
    638     FAILIF (GNUNET_OK !=
    639             activate_account (&acc,
    640                               "fake-order-account-status"));
    641 
    642     /* A fresh account has an expiration and no storage in use */
    643     FAILIF (SYNC_DB_ONE_RESULT !=
    644             SYNCDB_lookup_account_TR (&acc,
    645                                       &expiration,
    646                                       &storage_used_bytes,
    647                                       &block_count));
    648     FAILIF (GNUNET_TIME_absolute_is_zero (expiration.abs_time));
    649     FAILIF (0 != storage_used_bytes);
    650     FAILIF (0 != block_count);
    651 
    652     /* ... and the block it stores is reflected in both counters */
    653     RND_BLK (&nonce);
    654     GNUNET_CRYPTO_hash (data, sizeof data - 1, &bh);
    655     FAILIF (SYNC_DB_ONE_RESULT !=
    656             SYNCDB_append_block_TR (&acc,
    657                                     &nonce,
    658                                     NULL,
    659                                     &bh,
    660                                     sizeof data - 1,
    661                                     data,
    662                                     0,
    663                                     NULL,
    664                                     NULL,
    665                                     &fake_sig,
    666                                     &empty_refs,
    667                                     NULL,
    668                                     NULL,
    669                                     NULL));
    670     FAILIF (SYNC_DB_ONE_RESULT !=
    671             SYNCDB_lookup_account_TR (&acc,
    672                                       &expiration,
    673                                       &storage_used_bytes,
    674                                       &block_count));
    675     FAILIF (sizeof data - 1 != storage_used_bytes);
    676     FAILIF (1 != block_count);
    677 
    678     /* The blocks of other accounts must not be counted here */
    679     FAILIF (SYNC_DB_ONE_RESULT !=
    680             SYNCDB_lookup_account_TR (&account_pub,
    681                                       &expiration,
    682                                       &storage_used_bytes,
    683                                       &block_count));
    684     FAILIF (1 == block_count);
    685   }
    686 
    687   /* --- Object store/lookup tests --- */
    688   {
    689     struct SYNC_ObjectUID obj_uid;
    690     struct GNUNET_HashCode obj_hash;
    691     char obj_data[] = "objdata";
    692     int64_t refcount = 0;
    693     struct GNUNET_TIME_Timestamp exp;
    694     size_t data_sz = 0;
    695 
    696     RND_BLK (&obj_uid);
    697     GNUNET_CRYPTO_hash (obj_data, sizeof obj_data - 1, &obj_hash);
    698     FAILIF (SYNC_DB_ONE_RESULT !=
    699             SYNCDB_store_object_TR (
    700               &obj_uid,
    701               &account_pub,
    702               &obj_hash,
    703               GNUNET_TIME_UNIT_DAYS,
    704               sizeof obj_data - 1,
    705               obj_data));
    706 
    707     FAILIF (SYNC_DB_ONE_RESULT !=
    708             SYNCDB_lookup_object (
    709               &account_pub,
    710               &obj_hash,
    711               &refcount,
    712               &exp,
    713               &data_sz,
    714               NULL));
    715     FAILIF (refcount < 0);
    716 
    717     /* A missing object is a normal outcome, not a failure */
    718     {
    719       struct GNUNET_HashCode bogus_hash;
    720 
    721       GNUNET_CRYPTO_hash ("no-such-object",
    722                           14,
    723                           &bogus_hash);
    724       FAILIF (SYNC_DB_NO_RESULTS !=
    725               SYNCDB_lookup_object (&account_pub,
    726                                     &bogus_hash,
    727                                     &refcount,
    728                                     &exp,
    729                                     &data_sz,
    730                                     NULL));
    731     }
    732   }
    733 
    734   /* --- Referencing an object that was never uploaded --- */
    735   {
    736     struct SYNC_AccountPublicKeyP acc;
    737     struct SYNC_BlockNonce nonce;
    738     struct GNUNET_HashCode bh;
    739     struct SYNC_ObjectUID unknown_uid;
    740     const int16_t inc = 1;
    741     char data[] = "orphan";
    742 
    743     memset (&acc, 10, sizeof (acc));
    744     FAILIF (GNUNET_OK !=
    745             activate_account (&acc,
    746                               "fake-order-refs-missing"));
    747     RND_BLK (&nonce);
    748     RND_BLK (&unknown_uid);
    749     GNUNET_CRYPTO_hash (data, sizeof data - 1, &bh);
    750     FAILIF (SYNC_DB_INCONSISTENT_BACKUP !=
    751             SYNCDB_append_block_TR (&acc,
    752                                     &nonce,
    753                                     NULL,
    754                                     &bh,
    755                                     sizeof data - 1,
    756                                     data,
    757                                     1,
    758                                     &unknown_uid,
    759                                     &inc,
    760                                     &fake_sig,
    761                                     &empty_refs,
    762                                     NULL,
    763                                     NULL,
    764                                     NULL));
    765     /* the rejected append must be a no-op */
    766     FAILIF (0 != count_blocks (&acc));
    767   }
    768 
    769   /* --- A nonce that is already taken is a conflict --- */
    770   {
    771     struct SYNC_AccountPublicKeyP acc_a;
    772     struct SYNC_AccountPublicKeyP acc_b;
    773     struct SYNC_BlockNonce nonce;
    774     struct GNUNET_HashCode bh;
    775     char data[] = "shared-nonce";
    776 
    777     memset (&acc_a, 11, sizeof (acc_a));
    778     memset (&acc_b, 12, sizeof (acc_b));
    779     FAILIF (GNUNET_OK !=
    780             activate_account (&acc_a,
    781                               "fake-order-nonce-a"));
    782     FAILIF (GNUNET_OK !=
    783             activate_account (&acc_b,
    784                               "fake-order-nonce-b"));
    785     RND_BLK (&nonce);
    786     GNUNET_CRYPTO_hash (data, sizeof data - 1, &bh);
    787     FAILIF (SYNC_DB_ONE_RESULT !=
    788             SYNCDB_append_block_TR (&acc_a,
    789                                     &nonce,
    790                                     NULL,
    791                                     &bh,
    792                                     sizeof data - 1,
    793                                     data,
    794                                     0,
    795                                     NULL,
    796                                     NULL,
    797                                     &fake_sig,
    798                                     &empty_refs,
    799                                     NULL,
    800                                     NULL,
    801                                     NULL));
    802     FAILIF (SYNC_DB_OUTDATED_WRITE !=
    803             SYNCDB_append_block_TR (&acc_b,
    804                                     &nonce,
    805                                     NULL,
    806                                     &bh,
    807                                     sizeof data - 1,
    808                                     data,
    809                                     0,
    810                                     NULL,
    811                                     NULL,
    812                                     &fake_sig,
    813                                     &empty_refs,
    814                                     NULL,
    815                                     NULL,
    816                                     NULL));
    817     /* the rejected append must not have touched account B */
    818     FAILIF (0 != count_blocks (&acc_b));
    819   }
    820 
    821   /* --- Refcount lifecycle --- */
    822   {
    823     struct SYNC_AccountPublicKeyP acc;
    824     struct SYNC_BlockNonce nonce;
    825     struct GNUNET_HashCode bh;
    826     struct SYNC_ObjectUID uid;
    827     struct GNUNET_HashCode oh;
    828     const int16_t inc = 1;
    829     const int16_t dec = -1;
    830     const int16_t dec2 = -2;
    831     char data[] = "refcounted";
    832     char obj[] = "payload";
    833     int64_t refcount = 0;
    834     struct GNUNET_TIME_Timestamp exp;
    835     size_t data_sz = 0;
    836 
    837     memset (&acc, 13, sizeof (acc));
    838     FAILIF (GNUNET_OK !=
    839             activate_account (&acc,
    840                               "fake-order-refcount"));
    841     RND_BLK (&nonce);
    842     RND_BLK (&uid);
    843     GNUNET_CRYPTO_hash (data, sizeof data - 1, &bh);
    844     GNUNET_CRYPTO_hash (obj, sizeof obj - 1, &oh);
    845     FAILIF (SYNC_DB_ONE_RESULT !=
    846             SYNCDB_store_object_TR (&uid,
    847                                     &acc,
    848                                     &oh,
    849                                     GNUNET_TIME_UNIT_DAYS,
    850                                     sizeof obj - 1,
    851                                     obj));
    852     /* re-uploading the same UID is idempotent, not an error */
    853     FAILIF (SYNC_DB_ONE_RESULT !=
    854             SYNCDB_store_object_TR (&uid,
    855                                     &acc,
    856                                     &oh,
    857                                     GNUNET_TIME_UNIT_DAYS,
    858                                     sizeof obj - 1,
    859                                     obj));
    860     FAILIF (SYNC_DB_ONE_RESULT !=
    861             SYNCDB_append_block_TR (&acc,
    862                                     &nonce,
    863                                     NULL,
    864                                     &bh,
    865                                     sizeof data - 1,
    866                                     data,
    867                                     1,
    868                                     &uid,
    869                                     &inc,
    870                                     &fake_sig,
    871                                     &empty_refs,
    872                                     NULL,
    873                                     NULL,
    874                                     NULL));
    875     FAILIF (SYNC_DB_ONE_RESULT !=
    876             SYNCDB_lookup_object (&acc,
    877                                   &oh,
    878                                   &refcount,
    879                                   &exp,
    880                                   &data_sz,
    881                                   NULL));
    882     FAILIF (1 != refcount);
    883 
    884     /* decrementing below zero is refused, refcount untouched */
    885     FAILIF (SYNC_DB_INCONSISTENT_BACKUP !=
    886             SYNCDB_delete_block_TR (&acc,
    887                                     &nonce,
    888                                     NULL,
    889                                     NULL,
    890                                     &bh,
    891                                     1,
    892                                     &uid,
    893                                     &dec2,
    894                                     NULL,
    895                                     NULL,
    896                                     NULL,
    897                                     NULL,
    898                                     NULL,
    899                                     NULL));
    900     FAILIF (SYNC_DB_ONE_RESULT !=
    901             SYNCDB_lookup_object (&acc,
    902                                   &oh,
    903                                   &refcount,
    904                                   &exp,
    905                                   &data_sz,
    906                                   NULL));
    907     FAILIF (1 != refcount);
    908     /* ... and the block must still be there */
    909     FAILIF (1 != count_blocks (&acc));
    910 
    911     /* the matching decrement drops it to 0, deleting the object */
    912     FAILIF (SYNC_DB_ONE_RESULT !=
    913             SYNCDB_delete_block_TR (&acc,
    914                                     &nonce,
    915                                     NULL,
    916                                     NULL,
    917                                     &bh,
    918                                     1,
    919                                     &uid,
    920                                     &dec,
    921                                     NULL,
    922                                     NULL,
    923                                     NULL,
    924                                     NULL,
    925                                     NULL,
    926                                     NULL));
    927     FAILIF (SYNC_DB_NO_RESULTS !=
    928             SYNCDB_lookup_object (&acc,
    929                                   &oh,
    930                                   &refcount,
    931                                   &exp,
    932                                   &data_sz,
    933                                   NULL));
    934     FAILIF (0 != count_blocks (&acc));
    935   }
    936 
    937   /* --- Increments for the same UID are aggregated --- */
    938   {
    939     struct SYNC_AccountPublicKeyP acc;
    940     struct SYNC_BlockNonce nonce;
    941     struct GNUNET_HashCode bh;
    942     struct SYNC_ObjectUID uids[2];
    943     struct GNUNET_HashCode oh;
    944     const int16_t incs[2] = { -1, 1 };
    945     char data[] = "net-zero";
    946     char obj[] = "aggregated";
    947     int64_t refcount = 0;
    948     struct GNUNET_TIME_Timestamp exp;
    949     size_t data_sz = 0;
    950 
    951     memset (&acc, 14, sizeof (acc));
    952     FAILIF (GNUNET_OK !=
    953             activate_account (&acc,
    954                               "fake-order-aggregate"));
    955     RND_BLK (&nonce);
    956     RND_BLK (&uids[0]);
    957     uids[1] = uids[0];
    958     GNUNET_CRYPTO_hash (data, sizeof data - 1, &bh);
    959     GNUNET_CRYPTO_hash (obj, sizeof obj - 1, &oh);
    960     FAILIF (SYNC_DB_ONE_RESULT !=
    961             SYNCDB_store_object_TR (&uids[0],
    962                                     &acc,
    963                                     &oh,
    964                                     GNUNET_TIME_UNIT_DAYS,
    965                                     sizeof obj - 1,
    966                                     obj));
    967     FAILIF (SYNC_DB_ONE_RESULT !=
    968             SYNCDB_append_block_TR (&acc,
    969                                     &nonce,
    970                                     NULL,
    971                                     &bh,
    972                                     sizeof data - 1,
    973                                     data,
    974                                     2,
    975                                     uids,
    976                                     incs,
    977                                     &fake_sig,
    978                                     &empty_refs,
    979                                     NULL,
    980                                     NULL,
    981                                     NULL));
    982     /* refcount unchanged, and the object still exists */
    983     FAILIF (SYNC_DB_ONE_RESULT !=
    984             SYNCDB_lookup_object (&acc,
    985                                   &oh,
    986                                   &refcount,
    987                                   &exp,
    988                                   &data_sz,
    989                                   NULL));
    990     FAILIF (0 != refcount);
    991   }
    992 
    993   /* --- GC must not remove still-referenced objects --- */
    994   {
    995     struct SYNC_AccountPublicKeyP acc;
    996     struct SYNC_BlockNonce nonce;
    997     struct GNUNET_HashCode bh;
    998     struct SYNC_ObjectUID kept_uid;
    999     struct SYNC_ObjectUID swept_uid;
   1000     struct GNUNET_HashCode kept_oh;
   1001     struct GNUNET_HashCode swept_oh;
   1002     const int16_t inc = 1;
   1003     char data[] = "gc-block";
   1004     char kept[] = "still-referenced";
   1005     char swept[] = "unreferenced";
   1006     int64_t refcount = 0;
   1007     struct GNUNET_TIME_Timestamp exp;
   1008     size_t data_sz = 0;
   1009     struct GNUNET_TIME_Absolute future;
   1010 
   1011     memset (&acc, 15, sizeof (acc));
   1012     FAILIF (GNUNET_OK !=
   1013             activate_account (&acc,
   1014                               "fake-order-gc"));
   1015     RND_BLK (&nonce);
   1016     RND_BLK (&kept_uid);
   1017     RND_BLK (&swept_uid);
   1018     GNUNET_CRYPTO_hash (data, sizeof data - 1, &bh);
   1019     GNUNET_CRYPTO_hash (kept, sizeof kept - 1, &kept_oh);
   1020     GNUNET_CRYPTO_hash (swept, sizeof swept - 1, &swept_oh);
   1021     FAILIF (SYNC_DB_ONE_RESULT !=
   1022             SYNCDB_store_object_TR (&kept_uid,
   1023                                     &acc,
   1024                                     &kept_oh,
   1025                                     GNUNET_TIME_UNIT_DAYS,
   1026                                     sizeof kept - 1,
   1027                                     kept));
   1028     FAILIF (SYNC_DB_ONE_RESULT !=
   1029             SYNCDB_store_object_TR (&swept_uid,
   1030                                     &acc,
   1031                                     &swept_oh,
   1032                                     GNUNET_TIME_UNIT_DAYS,
   1033                                     sizeof swept - 1,
   1034                                     swept));
   1035     FAILIF (SYNC_DB_ONE_RESULT !=
   1036             SYNCDB_append_block_TR (&acc,
   1037                                     &nonce,
   1038                                     NULL,
   1039                                     &bh,
   1040                                     sizeof data - 1,
   1041                                     data,
   1042                                     1,
   1043                                     &kept_uid,
   1044                                     &inc,
   1045                                     &fake_sig,
   1046                                     &empty_refs,
   1047                                     NULL,
   1048                                     NULL,
   1049                                     NULL));
   1050     /* Leave accounts and payments alone, only sweep objects */
   1051     future = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_YEARS);
   1052     FAILIF (GNUNET_OK !=
   1053             SYNCDB_gc (GNUNET_TIME_UNIT_ZERO_ABS,
   1054                        GNUNET_TIME_UNIT_ZERO_ABS,
   1055                        future));
   1056     /* the referenced object survives ... */
   1057     FAILIF (SYNC_DB_ONE_RESULT !=
   1058             SYNCDB_lookup_object (&acc,
   1059                                   &kept_oh,
   1060                                   &refcount,
   1061                                   &exp,
   1062                                   &data_sz,
   1063                                   NULL));
   1064     FAILIF (1 != refcount);
   1065     /* ... the unreferenced one is collected */
   1066     FAILIF (SYNC_DB_NO_RESULTS !=
   1067             SYNCDB_lookup_object (&acc,
   1068                                   &swept_oh,
   1069                                   &refcount,
   1070                                   &exp,
   1071                                   &data_sz,
   1072                                   NULL));
   1073   }
   1074 
   1075   ts = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_YEARS);
   1076   FAILIF (GNUNET_OK !=
   1077           SYNCDB_gc (ts,
   1078                      ts,
   1079                      ts));
   1080   result = 0;
   1081 drop:
   1082   GNUNET_break (GNUNET_OK ==
   1083                 SYNCDB_drop_tables ());
   1084   SYNCDB_fini ();
   1085 }
   1086 
   1087 
   1088 int
   1089 main (int argc,
   1090       char *const argv[])
   1091 {
   1092   const char *plugin_name;
   1093   char *config_filename;
   1094   struct GNUNET_CONFIGURATION_Handle *cfg;
   1095 
   1096   (void) argc;
   1097   result = EXIT_FAILURE;
   1098   /* the database backend is the suffix of our own binary name */
   1099   if (NULL == (plugin_name = strrchr (argv[0], (int) '-')))
   1100   {
   1101     GNUNET_break (0);
   1102     return EXIT_FAILURE;
   1103   }
   1104   plugin_name++;
   1105   GNUNET_log_setup (argv[0],
   1106                     "DEBUG",
   1107                     NULL);
   1108   GNUNET_asprintf (&config_filename,
   1109                    "test_sync_db_%s.conf",
   1110                    plugin_name);
   1111   cfg = GNUNET_CONFIGURATION_create (SYNC_project_data ());
   1112   if (GNUNET_OK !=
   1113       GNUNET_CONFIGURATION_parse (cfg,
   1114                                   config_filename))
   1115   {
   1116     GNUNET_break (0);
   1117     GNUNET_CONFIGURATION_destroy (cfg);
   1118     GNUNET_free (config_filename);
   1119     return EXIT_NOTCONFIGURED;
   1120   }
   1121   GNUNET_SCHEDULER_run (&run, cfg);
   1122   GNUNET_CONFIGURATION_destroy (cfg);
   1123   GNUNET_free (config_filename);
   1124   return result;
   1125 }
   1126 
   1127 
   1128 /* end of test_sync_db.c */