exchange

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

test_exchange_api.c (44813B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2014--2022 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify
      6   it under the terms of the GNU General Public License as
      7   published by the Free Software Foundation; either version 3, or
      8   (at your option) any later version.
      9 
     10   TALER is distributed in the hope that it will be useful, but
     11   WITHOUT ANY WARRANTY; without even the implied warranty of
     12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13   GNU General Public License for more details.
     14 
     15   You should have received a copy of the GNU General Public
     16   License along with TALER; see the file COPYING.  If not, see
     17   <http://www.gnu.org/licenses/>
     18 */
     19 /**
     20  * @file testing/test_exchange_api.c
     21  * @brief testcase to test exchange's HTTP API interface
     22  * @author Sree Harsha Totakura <sreeharsha@totakura.in>
     23  * @author Christian Grothoff
     24  * @author Marcello Stanisci
     25  */
     26 #include "taler/taler_util.h"
     27 #include "taler/taler_signatures.h"
     28 #include "taler/taler_json_lib.h"
     29 #include <gnunet/gnunet_util_lib.h>
     30 #include <gnunet/gnunet_testing_lib.h>
     31 #include <microhttpd.h>
     32 #include "taler/taler_bank_service.h"
     33 #include "taler/taler_testing_lib.h"
     34 
     35 /**
     36  * Configuration file we use.  One (big) configuration is used
     37  * for the various components for this test.
     38  */
     39 static char *config_file;
     40 
     41 /**
     42  * Special configuration file to use when we want reserves
     43  * to expire 'immediately'.
     44  */
     45 static char *config_file_expire_reserve_now;
     46 
     47 /**
     48  * Our credentials.
     49  */
     50 static struct TALER_TESTING_Credentials cred;
     51 
     52 /**
     53  * Some tests behave differently when using CS as we cannot
     54  * reuse the coin private key for different denominations
     55  * due to the derivation of it with the /csr values. Hence
     56  * some tests behave differently in CS mode, hence this
     57  * flag.
     58  */
     59 static bool uses_cs;
     60 
     61 /**
     62  * Execute the taler-exchange-wirewatch command with
     63  * our configuration file.
     64  *
     65  * @param label label to use for the command.
     66  */
     67 #define CMD_EXEC_WIREWATCH(label) \
     68         TALER_TESTING_cmd_exec_wirewatch2 (label, config_file, \
     69                                            "exchange-account-2")
     70 
     71 /**
     72  * Execute the taler-exchange-aggregator, closer and transfer commands with
     73  * our configuration file.
     74  *
     75  * @param label label to use for the command.
     76  */
     77 #define CMD_EXEC_AGGREGATOR(label) \
     78         TALER_TESTING_cmd_sleep ("sleep-before-aggregator", 2), \
     79         TALER_TESTING_cmd_exec_aggregator (label "-aggregator", config_file), \
     80         TALER_TESTING_cmd_exec_transfer (label "-transfer", config_file)
     81 
     82 
     83 /**
     84  * Run wire transfer of funds from some user's account to the
     85  * exchange.
     86  *
     87  * @param label label to use for the command.
     88  * @param amount amount to transfer, i.e. "EUR:1"
     89  */
     90 #define CMD_TRANSFER_TO_EXCHANGE(label,amount) \
     91         TALER_TESTING_cmd_admin_add_incoming (label, amount, \
     92                                               &cred.ba,                \
     93                                               cred.user42_payto)
     94 
     95 /**
     96  * Main function that will tell the interpreter what commands to
     97  * run.
     98  *
     99  * @param cls closure
    100  * @param is interpreter we use to run commands
    101  */
    102 static void
    103 run (void *cls,
    104      struct TALER_TESTING_Interpreter *is)
    105 {
    106   /**
    107    * Test withdrawal plus spending.
    108    */
    109   struct TALER_TESTING_Command withdraw[] = {
    110     /**
    111      * Move money to the exchange's bank account.
    112      */
    113     CMD_TRANSFER_TO_EXCHANGE ("create-reserve-1",
    114                               "EUR:6.02"),
    115     TALER_TESTING_cmd_reserve_poll ("poll-reserve-1",
    116                                     "create-reserve-1",
    117                                     "EUR:6.02",
    118                                     GNUNET_TIME_UNIT_MINUTES,
    119                                     MHD_HTTP_OK),
    120     TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-1",
    121                                                  "EUR:6.02",
    122                                                  cred.user42_payto,
    123                                                  cred.exchange_payto,
    124                                                  "create-reserve-1"),
    125     /**
    126      * Make a reserve exist, according to the previous
    127      * transfer.
    128      */
    129     CMD_EXEC_WIREWATCH ("wirewatch-1"),
    130     TALER_TESTING_cmd_reserve_poll_finish ("finish-poll-reserve-1",
    131                                            GNUNET_TIME_relative_multiply (
    132                                              GNUNET_TIME_UNIT_SECONDS,
    133                                              2),
    134                                            "poll-reserve-1"),
    135     /**
    136      * Withdraw EUR:5.
    137      */
    138     TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1",
    139                                        "create-reserve-1",
    140                                        "EUR:5",
    141                                        0, /* age restriction off */
    142                                        MHD_HTTP_OK),
    143     /**
    144      * Idempotent withdrawal.  Note that in the case of CS, this is _not_
    145      * idempotent because the blinding nonces still differ, so instead,
    146      * it is an overcharging of the reserve.
    147      */
    148     TALER_TESTING_cmd_withdraw_amount_reuse_key ("withdraw-coin-1-idem",
    149                                                  "create-reserve-1",
    150                                                  "EUR:5",
    151                                                  0, /* age restriction off */
    152                                                  "withdraw-coin-1",
    153                                                  (uses_cs)
    154                                                  ? MHD_HTTP_CONFLICT
    155                                                  : MHD_HTTP_OK),
    156     /**
    157     * Withdraw EUR:1 using the SAME private coin key as for the previous coin
    158     * (in violation of the specification, to be detected on spending!).
    159     * However, note that this does NOT work with 'CS', as for a different
    160     * denomination we get different R0/R1 values from the exchange, and
    161     * thus will generate a different coin private key as R0/R1 are hashed
    162     * into the coin priv. So here, we fail to 'reuse' the key due to the
    163     * cryptographic construction!
    164     */
    165     TALER_TESTING_cmd_withdraw_amount_reuse_key ("withdraw-coin-1x",
    166                                                  "create-reserve-1",
    167                                                  "EUR:1",
    168                                                  0, /* age restriction off */
    169                                                  "withdraw-coin-1",
    170                                                  MHD_HTTP_OK),
    171     /**
    172      * Check the reserve is depleted.
    173      */
    174     TALER_TESTING_cmd_status ("status-1",
    175                               "create-reserve-1",
    176                               "EUR:0",
    177                               MHD_HTTP_OK),
    178     /*
    179      * Try to overdraw.
    180      */
    181     TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-2",
    182                                        "create-reserve-1",
    183                                        "EUR:5",
    184                                        0, /* age restriction off */
    185                                        MHD_HTTP_CONFLICT),
    186     TALER_TESTING_cmd_end ()
    187   };
    188 
    189   struct TALER_TESTING_Command spend[] = {
    190     /**
    191      * Spend the coin.
    192      */
    193     TALER_TESTING_cmd_set_var (
    194       "account-priv",
    195       TALER_TESTING_cmd_deposit (
    196         "deposit-simple-fail-kyc",
    197         "withdraw-coin-1",
    198         0,
    199         cred.user42_payto,
    200         "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
    201         GNUNET_TIME_UNIT_ZERO,
    202         "EUR:5",
    203         MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS)),
    204     TALER_TESTING_cmd_admin_add_kycauth (
    205       "kyc-auth-transfer",
    206       "EUR:0.01",
    207       &cred.ba,
    208       cred.user42_payto,
    209       "deposit-simple-fail-kyc"),
    210     CMD_EXEC_WIREWATCH (
    211       "import-kyc-account-withdraw"),
    212     TALER_TESTING_cmd_deposit_replay (
    213       "deposit-simple",
    214       "deposit-simple-fail-kyc",
    215       MHD_HTTP_OK),
    216     TALER_TESTING_cmd_deposit_replay (
    217       "deposit-simple-replay-1",
    218       "deposit-simple",
    219       MHD_HTTP_OK),
    220     TALER_TESTING_cmd_sleep (
    221       "sleep-before-deposit-replay",
    222       1),
    223     TALER_TESTING_cmd_deposit_replay (
    224       "deposit-simple-replay-2",
    225       "deposit-simple",
    226       MHD_HTTP_OK),
    227     /* This creates a conflict, as we have the same coin public key (reuse!),
    228        but different denomination public keys (which is not allowed).
    229        However, note that this does NOT work with 'CS', as for a different
    230        denomination we get different R0/R1 values from the exchange, and
    231        thus will generate a different coin private key as R0/R1 are hashed
    232        into the coin priv. So here, we fail to 'reuse' the key due to the
    233        cryptographic construction! */
    234     TALER_TESTING_cmd_deposit (
    235       "deposit-reused-coin-key-failure",
    236       "withdraw-coin-1x",
    237       0,
    238       cred.user42_payto,
    239       "{\"items\":[{\"name\":\"conflicting ice cream\",\"value\":1}]}",
    240       GNUNET_TIME_UNIT_ZERO,
    241       "EUR:1",
    242       uses_cs
    243       ? MHD_HTTP_OK
    244       : MHD_HTTP_CONFLICT),
    245     /**
    246      * Try to double spend using different wire details.
    247      */
    248     TALER_TESTING_cmd_admin_add_kycauth (
    249       "kyc-auth-transfer-2",
    250       "EUR:0.01",
    251       &cred.ba,
    252       cred.user43_payto,
    253       "deposit-simple-fail-kyc"),
    254     CMD_EXEC_WIREWATCH (
    255       "import-kyc-account-1"),
    256     TALER_TESTING_cmd_deposit (
    257       "deposit-double-1",
    258       "withdraw-coin-1",
    259       0,
    260       cred.user43_payto,
    261       "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
    262       GNUNET_TIME_UNIT_ZERO,
    263       "EUR:5",
    264       MHD_HTTP_CONFLICT),
    265     /* Try to double spend using a different transaction id.
    266      * The test needs the contract terms to differ. This
    267      * is currently the case because of the "timestamp" field,
    268      * which is set automatically by #TALER_TESTING_cmd_deposit().
    269      * This could theoretically fail if at some point a deposit
    270      * command executes in less than 1 ms. */
    271     TALER_TESTING_cmd_deposit (
    272       "deposit-double-1",
    273       "withdraw-coin-1",
    274       0,
    275       cred.user43_payto,
    276       "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
    277       GNUNET_TIME_UNIT_ZERO,
    278       "EUR:5",
    279       MHD_HTTP_CONFLICT),
    280     /**
    281      * Try to double spend with different proposal.
    282      */
    283     TALER_TESTING_cmd_deposit (
    284       "deposit-double-2",
    285       "withdraw-coin-1",
    286       0,
    287       cred.user43_payto,
    288       "{\"items\":[{\"name\":\"ice cream\",\"value\":2}]}",
    289       GNUNET_TIME_UNIT_ZERO,
    290       "EUR:5",
    291       MHD_HTTP_CONFLICT),
    292     TALER_TESTING_cmd_end ()
    293   };
    294 
    295   struct TALER_TESTING_Command refresh[] = {
    296     /**
    297      * Try to melt the coin that shared the private key with another
    298      * coin (should fail). Note that in the CS-case, we fail also
    299      * with MHD_HTTP_CONFLICT, but for a different reason: here it
    300      * is not a denomination conflict, but a double-spending conflict.
    301      */
    302     TALER_TESTING_cmd_melt (
    303       "refresh-melt-reused-coin-key-failure",
    304       "withdraw-coin-1x",
    305       MHD_HTTP_CONFLICT,
    306       NULL),
    307 
    308     /* Fill reserve with EUR:5, 1ct is for fees. */
    309     CMD_TRANSFER_TO_EXCHANGE (
    310       "refresh-create-reserve-1",
    311       "EUR:5.01"),
    312     TALER_TESTING_cmd_check_bank_admin_transfer (
    313       "ck-refresh-create-reserve-1",
    314       "EUR:5.01",
    315       cred.user42_payto,
    316       cred.exchange_payto,
    317       "refresh-create-reserve-1"),
    318     /**
    319      * Make previous command effective.
    320      */
    321     CMD_EXEC_WIREWATCH ("wirewatch-2"),
    322     /**
    323      * Withdraw EUR:5.
    324      */
    325     TALER_TESTING_cmd_withdraw_amount (
    326       "refresh-withdraw-coin-1",
    327       "refresh-create-reserve-1",
    328       "EUR:5",
    329       0,                                  /* age restriction off */
    330       MHD_HTTP_OK),
    331     /* Try to partially spend (deposit) 1 EUR of the 5 EUR coin
    332      * (in full) (merchant would receive EUR:0.99 due to 1 ct
    333      * deposit fee)
    334      */
    335     TALER_TESTING_cmd_deposit (
    336       "refresh-deposit-partial",
    337       "refresh-withdraw-coin-1",
    338       0,
    339       cred.user42_payto,
    340       "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:1\"}]}",
    341       GNUNET_TIME_UNIT_ZERO,
    342       "EUR:1",
    343       MHD_HTTP_OK),
    344     /**
    345      * Melt the rest of the coin's value
    346      * (EUR:4.00 = 3x EUR:1.03 + 7x EUR:0.13) */
    347     TALER_TESTING_cmd_melt_double (
    348       "refresh-melt-1",
    349       "refresh-withdraw-coin-1",
    350       MHD_HTTP_OK,
    351       NULL),
    352     /**
    353      * Complete (successful) melt operation, and
    354      * withdraw the coins
    355      */
    356     TALER_TESTING_cmd_melt_reveal (
    357       "refresh-reveal-1",
    358       "refresh-melt-1",
    359       MHD_HTTP_OK),
    360     /**
    361      * Do it again to check idempotency
    362      */
    363     TALER_TESTING_cmd_melt_reveal (
    364       "refresh-reveal-1-idempotency",
    365       "refresh-melt-1",
    366       MHD_HTTP_OK),
    367     /**
    368      * Try to spend a refreshed EUR:1 coin
    369      */
    370     TALER_TESTING_cmd_deposit (
    371       "refresh-deposit-refreshed-1a",
    372       "refresh-reveal-1-idempotency",
    373       0,
    374       cred.user42_payto,
    375       "{\"items\":[{\"name\":\"ice cream\",\"value\":3}]}",
    376       GNUNET_TIME_UNIT_ZERO,
    377       "EUR:1",
    378       MHD_HTTP_OK),
    379     /**
    380      * Try to spend a refreshed EUR:0.1 coin
    381      */
    382     TALER_TESTING_cmd_deposit (
    383       "refresh-deposit-refreshed-1b",
    384       "refresh-reveal-1",
    385       3,
    386       cred.user43_payto,
    387       "{\"items\":[{\"name\":\"cheap ice cream\",\"value\":3}]}",
    388       GNUNET_TIME_UNIT_ZERO,
    389       "EUR:0.1",
    390       MHD_HTTP_OK),
    391     /* Test running a failing melt operation (same operation
    392      * again must fail) */
    393     TALER_TESTING_cmd_melt (
    394       "refresh-melt-failing",
    395       "refresh-withdraw-coin-1",
    396       MHD_HTTP_CONFLICT,
    397       NULL),
    398     /* Test running a failing melt operation (on a coin that
    399        was itself revealed and subsequently deposited) */
    400     TALER_TESTING_cmd_melt (
    401       "refresh-melt-failing-2",
    402       "refresh-reveal-1",
    403       MHD_HTTP_CONFLICT,
    404       NULL),
    405 
    406     TALER_TESTING_cmd_end ()
    407   };
    408 
    409   /**
    410    * Test withdrawal with age restriction.  Success is expected, so it MUST be
    411    * called _after_ TALER_TESTING_cmd_exec_offline_sign_extensions is called,
    412    * i. e. age restriction is activated in the exchange!
    413    *
    414    * FIXME[oec]: create a test that tries to withdraw coins with age restriction but
    415    * (expectedly) fails because the exchange doesn't support age restriction
    416    * yet.
    417    */
    418   struct TALER_TESTING_Command withdraw_age[] = {
    419     /**
    420      * Move money to the exchange's bank account.
    421      */
    422     CMD_TRANSFER_TO_EXCHANGE (
    423       "create-reserve-age",
    424       "EUR:6.01"),
    425     TALER_TESTING_cmd_check_bank_admin_transfer (
    426       "check-create-reserve-age",
    427       "EUR:6.01",
    428       cred.user42_payto,
    429       cred.exchange_payto,
    430       "create-reserve-age"),
    431     /**
    432      * Make a reserve exist, according to the previous
    433      * transfer.
    434      */
    435     CMD_EXEC_WIREWATCH ("wirewatch-age"),
    436     /**
    437      * Withdraw EUR:5.
    438      */
    439     TALER_TESTING_cmd_withdraw_amount (
    440       "withdraw-coin-age-1",
    441       "create-reserve-age",
    442       "EUR:5",
    443       13,
    444       MHD_HTTP_OK),
    445 
    446     TALER_TESTING_cmd_end ()
    447   };
    448 
    449   struct TALER_TESTING_Command spend_age[] = {
    450     /**
    451      * Spend the coin.
    452      */
    453     TALER_TESTING_cmd_deposit (
    454       "deposit-simple-age",
    455       "withdraw-coin-age-1",
    456       0,
    457       cred.user42_payto,
    458       "{\"items\":[{\"name\":\"unique ice cream\",\"value\":1}]}",
    459       GNUNET_TIME_UNIT_ZERO,
    460       "EUR:4.99",
    461       MHD_HTTP_OK),
    462     TALER_TESTING_cmd_deposit_replay (
    463       "deposit-simple-replay-age",
    464       "deposit-simple-age",
    465       MHD_HTTP_OK),
    466     TALER_TESTING_cmd_deposit_replay (
    467       "deposit-simple-replay-age-1",
    468       "deposit-simple-age",
    469       MHD_HTTP_OK),
    470     TALER_TESTING_cmd_sleep (
    471       "sleep-before-age-deposit-replay",
    472       1),
    473     TALER_TESTING_cmd_deposit_replay (
    474       "deposit-simple-replay-age-2",
    475       "deposit-simple-age",
    476       MHD_HTTP_OK),
    477     TALER_TESTING_cmd_end ()
    478   };
    479 
    480   struct TALER_TESTING_Command track[] = {
    481     /* Try resolving a deposit's WTID, as we never triggered
    482      * execution of transactions, the answer should be that
    483      * the exchange knows about the deposit, but has no WTID yet.
    484      */
    485     TALER_TESTING_cmd_deposits_get (
    486       "deposit-wtid-found",
    487       "deposit-simple",
    488       0,
    489       MHD_HTTP_ACCEPTED,
    490       NULL),
    491     /* Try resolving a deposit's WTID for a failed deposit.
    492      * As the deposit failed, the answer should be that the
    493      * exchange does NOT know about the deposit.
    494      */
    495     TALER_TESTING_cmd_deposits_get (
    496       "deposit-wtid-failing",
    497       "deposit-double-2",
    498       0,
    499       MHD_HTTP_NOT_FOUND,
    500       NULL),
    501     /* Try resolving an undefined (all zeros) WTID; this
    502      * should fail as obviously the exchange didn't use that
    503      * WTID value for any transaction.
    504      */
    505     TALER_TESTING_cmd_track_transfer_empty (
    506       "wire-deposit-failing",
    507       NULL,
    508       MHD_HTTP_NOT_FOUND),
    509     /* Run transfers. */
    510     CMD_EXEC_AGGREGATOR ("run-aggregator"),
    511     /**
    512      * Check all the transfers took place.
    513      */
    514     TALER_TESTING_cmd_check_bank_transfer (
    515       "check_bank_transfer-42-aggregate",
    516       cred.exchange_url,
    517       /* In case of CS, one transaction above succeeded that
    518          failed for RSA, hence we get a larger amount here */
    519       uses_cs ? "EUR:14.91" : "EUR:13.92",
    520       cred.exchange_payto,
    521       cred.user42_payto),
    522     TALER_TESTING_cmd_check_bank_transfer (
    523       "check_bank_transfer-43-aggregate",
    524       cred.exchange_url,
    525       "EUR:0.17",
    526       cred.exchange_payto,
    527       cred.user43_payto),
    528     TALER_TESTING_cmd_check_bank_empty ("check_bank_empty"),
    529     TALER_TESTING_cmd_deposits_get (
    530       "deposit-wtid-ok",
    531       "deposit-simple",
    532       0,
    533       MHD_HTTP_OK,
    534       "check_bank_transfer-42-aggregate"),
    535     TALER_TESTING_cmd_track_transfer (
    536       "wire-deposit-success-bank",
    537       "check_bank_transfer-42-aggregate",
    538       MHD_HTTP_OK,
    539       uses_cs ? "EUR:14.91" : "EUR:13.92",
    540       "EUR:0.01"),
    541     TALER_TESTING_cmd_track_transfer (
    542       "wire-deposits-success-wtid",
    543       "check_bank_transfer-43-aggregate",
    544       MHD_HTTP_OK,
    545       "EUR:0.17",
    546       "EUR:0.01"),
    547     TALER_TESTING_cmd_end ()
    548   };
    549 
    550   /**
    551    * This block checks whether a wire deadline
    552    * very far in the future does NOT get aggregated now.
    553    */
    554   struct TALER_TESTING_Command unaggregation[] = {
    555     TALER_TESTING_cmd_check_bank_empty ("far-future-aggregation-a"),
    556     CMD_TRANSFER_TO_EXCHANGE (
    557       "create-reserve-unaggregated",
    558       "EUR:5.01"),
    559     /* "consume" reserve creation transfer.  */
    560     TALER_TESTING_cmd_check_bank_admin_transfer (
    561       "check-create-reserve-unaggregated",
    562       "EUR:5.01",
    563       cred.user42_payto,
    564       cred.exchange_payto,
    565       "create-reserve-unaggregated"),
    566     CMD_EXEC_WIREWATCH ("wirewatch-unaggregated"),
    567     TALER_TESTING_cmd_withdraw_amount (
    568       "withdraw-coin-unaggregated",
    569       "create-reserve-unaggregated",
    570       "EUR:5",
    571       0,                                  /* age restriction off */
    572       MHD_HTTP_OK),
    573     TALER_TESTING_cmd_deposit (
    574       "deposit-unaggregated",
    575       "withdraw-coin-unaggregated",
    576       0,
    577       cred.user43_payto,
    578       "{\"items\":[{\"name\":\"different ice cream\",\"value\":1}]}",
    579       GNUNET_TIME_relative_multiply (
    580         GNUNET_TIME_UNIT_YEARS,
    581         3000),
    582       "EUR:5",
    583       MHD_HTTP_OK),
    584     CMD_EXEC_AGGREGATOR ("aggregation-attempt"),
    585 
    586     TALER_TESTING_cmd_check_bank_empty (
    587       "far-future-aggregation-b"),
    588 
    589     TALER_TESTING_cmd_end ()
    590   };
    591 
    592   struct TALER_TESTING_Command refresh_age[] = {
    593     /* Fill reserve with EUR:5, 1ct is for fees. */
    594     CMD_TRANSFER_TO_EXCHANGE (
    595       "refresh-create-reserve-age-1",
    596       "EUR:6.01"),
    597     TALER_TESTING_cmd_check_bank_admin_transfer (
    598       "ck-refresh-create-reserve-age-1",
    599       "EUR:6.01",
    600       cred.user42_payto,
    601       cred.exchange_payto,
    602       "refresh-create-reserve-age-1"),
    603     /**
    604      * Make previous command effective.
    605      */
    606     CMD_EXEC_WIREWATCH ("wirewatch-age-2"),
    607     /**
    608      * Withdraw EUR:7 with age restriction for age 13.
    609      */
    610     TALER_TESTING_cmd_withdraw_amount (
    611       "refresh-withdraw-coin-age-1",
    612       "refresh-create-reserve-age-1",
    613       "EUR:5",
    614       13,
    615       MHD_HTTP_OK),
    616     /* Try to partially spend (deposit) 1 EUR of the 5 EUR coin
    617      * (in full) (merchant would receive EUR:0.99 due to 1 ct
    618      * deposit fee)
    619      */
    620     TALER_TESTING_cmd_deposit (
    621       "refresh-deposit-partial-age",
    622       "refresh-withdraw-coin-age-1",
    623       0,
    624       cred.user42_payto,
    625       "{\"items\":[{\"name\":\"special ice cream\",\"value\":\"EUR:1\"}]}",
    626       GNUNET_TIME_UNIT_ZERO,
    627       "EUR:1",
    628       MHD_HTTP_OK),
    629     /**
    630      * Melt the rest of the coin's value
    631      * (EUR:4.00 = 3x EUR:1.03 + 7x EUR:0.13) */
    632     TALER_TESTING_cmd_melt_double (
    633       "refresh-melt-age-1",
    634       "refresh-withdraw-coin-age-1",
    635       MHD_HTTP_OK,
    636       NULL),
    637     /**
    638      * Complete (successful) melt operation, and
    639      * withdraw the coins
    640      */
    641     TALER_TESTING_cmd_melt_reveal (
    642       "refresh-reveal-age-1",
    643       "refresh-melt-age-1",
    644       MHD_HTTP_OK),
    645     /**
    646      * Do it again to check idempotency
    647      */
    648     TALER_TESTING_cmd_melt_reveal (
    649       "refresh-reveal-age-1-idempotency",
    650       "refresh-melt-age-1",
    651       MHD_HTTP_OK),
    652     /**
    653      * Try to spend a refreshed EUR:1 coin
    654      */
    655     TALER_TESTING_cmd_deposit (
    656       "refresh-deposit-refreshed-age-1a",
    657       "refresh-reveal-age-1-idempotency",
    658       0,
    659       cred.user42_payto,
    660       "{\"items\":[{\"name\":\"garlic ice cream\",\"value\":3}]}",
    661       GNUNET_TIME_UNIT_ZERO,
    662       "EUR:1",
    663       MHD_HTTP_OK),
    664     /**
    665      * Try to spend a refreshed EUR:0.1 coin
    666      */
    667     TALER_TESTING_cmd_deposit (
    668       "refresh-deposit-refreshed-age-1b",
    669       "refresh-reveal-age-1",
    670       3,
    671       cred.user43_payto,
    672       "{\"items\":[{\"name\":\"spicy ice cream\",\"value\":3}]}",
    673       GNUNET_TIME_UNIT_ZERO,
    674       "EUR:0.1",
    675       MHD_HTTP_OK),
    676     /* Test running a failing melt operation (same operation
    677      * again must fail) */
    678     TALER_TESTING_cmd_melt (
    679       "refresh-melt-failing-age",
    680       "refresh-withdraw-coin-age-1",
    681       MHD_HTTP_CONFLICT,
    682       NULL),
    683     /* Test running a failing melt operation (on a coin that
    684        was itself revealed and subsequently deposited) */
    685     TALER_TESTING_cmd_melt (
    686       "refresh-melt-failing-age-2",
    687       "refresh-reveal-age-1",
    688       MHD_HTTP_CONFLICT,
    689       NULL),
    690     TALER_TESTING_cmd_end ()
    691   };
    692 
    693   /**
    694    * This block exercises the aggretation logic by making two payments
    695    * to the same merchant.
    696    */
    697   struct TALER_TESTING_Command aggregation[] = {
    698     CMD_TRANSFER_TO_EXCHANGE ("create-reserve-aggtest",
    699                               "EUR:5.01"),
    700     /* "consume" reserve creation transfer.  */
    701     TALER_TESTING_cmd_check_bank_admin_transfer (
    702       "check-create-reserve-aggtest",
    703       "EUR:5.01",
    704       cred.user42_payto,
    705       cred.exchange_payto,
    706       "create-reserve-aggtest"),
    707     CMD_EXEC_WIREWATCH ("wirewatch-aggtest"),
    708     TALER_TESTING_cmd_withdraw_amount (
    709       "withdraw-coin-aggtest",
    710       "create-reserve-aggtest",
    711       "EUR:5",
    712       0,                                  /* age restriction off */
    713       MHD_HTTP_OK),
    714     TALER_TESTING_cmd_deposit (
    715       "deposit-aggtest-1",
    716       "withdraw-coin-aggtest",
    717       0,
    718       cred.user43_payto,
    719       "{\"items\":[{\"name\":\"cinamon ice cream\",\"value\":1}]}",
    720       GNUNET_TIME_UNIT_ZERO,
    721       "EUR:2",
    722       MHD_HTTP_OK),
    723     TALER_TESTING_cmd_deposit_with_ref (
    724       "deposit-aggtest-2",
    725       "withdraw-coin-aggtest",
    726       0,
    727       cred.user43_payto,
    728       "{\"items\":[{\"name\":\"foo bar\",\"value\":1}]}",
    729       GNUNET_TIME_UNIT_ZERO,
    730       "EUR:2",
    731       MHD_HTTP_OK,
    732       "deposit-aggtest-1"),
    733     CMD_EXEC_AGGREGATOR ("aggregation-aggtest"),
    734     TALER_TESTING_cmd_check_bank_transfer (
    735       "check-bank-transfer-aggtest",
    736       cred.exchange_url,
    737       "EUR:3.97",
    738       cred.exchange_payto,
    739       cred.user43_payto),
    740     TALER_TESTING_cmd_check_bank_empty ("check-bank-empty-aggtest"),
    741     TALER_TESTING_cmd_end ()
    742   };
    743 
    744   struct TALER_TESTING_Command refund[] = {
    745     /**
    746      * Fill reserve with EUR:5.01, as withdraw fee is 1 ct per
    747      * config.
    748      */
    749     CMD_TRANSFER_TO_EXCHANGE (
    750       "create-reserve-r1",
    751       "EUR:5.01"),
    752     TALER_TESTING_cmd_check_bank_admin_transfer (
    753       "check-create-reserve-r1",
    754       "EUR:5.01",
    755       cred.user42_payto,
    756       cred.exchange_payto,
    757       "create-reserve-r1"),
    758     /**
    759      * Run wire-watch to trigger the reserve creation.
    760      */
    761     CMD_EXEC_WIREWATCH ("wirewatch-3"),
    762     /* Withdraw a 5 EUR coin, at fee of 1 ct */
    763     TALER_TESTING_cmd_withdraw_amount (
    764       "withdraw-coin-r1",
    765       "create-reserve-r1",
    766       "EUR:5",
    767       0,                                  /* age restriction off */
    768       MHD_HTTP_OK),
    769     /**
    770      * Spend 5 EUR of the 5 EUR coin (in full) (merchant would
    771      * receive EUR:4.99 due to 1 ct deposit fee)
    772      */
    773     TALER_TESTING_cmd_deposit (
    774       "deposit-refund-1",
    775       "withdraw-coin-r1",
    776       0,
    777       cred.user42_payto,
    778       "{\"items\":[{\"name\":\"blue ice cream\",\"value\":\"EUR:5\"}]}",
    779       GNUNET_TIME_UNIT_MINUTES,
    780       "EUR:5",
    781       MHD_HTTP_OK),
    782     /**
    783      * Run transfers. Should do nothing as refund deadline blocks it
    784      */
    785     CMD_EXEC_AGGREGATOR ("run-aggregator-refund"),
    786     /* Check that aggregator didn't do anything, as expected.
    787      * Note, this operation takes two commands: one to "flush"
    788      * the preliminary transfer (used to withdraw) from the
    789      * fakebank and the second to actually check there are not
    790      * other transfers around. */
    791     TALER_TESTING_cmd_check_bank_empty ("check_bank_transfer-pre-refund"),
    792     TALER_TESTING_cmd_refund_with_id (
    793       "refund-ok",
    794       MHD_HTTP_OK,
    795       "EUR:3",
    796       "deposit-refund-1",
    797       3),
    798     TALER_TESTING_cmd_refund_with_id (
    799       "refund-ok-double",
    800       MHD_HTTP_OK,
    801       "EUR:3",
    802       "deposit-refund-1",
    803       3),
    804     /* Previous /refund(s) had id == 0.  */
    805     TALER_TESTING_cmd_refund_with_id (
    806       "refund-conflicting",
    807       MHD_HTTP_CONFLICT,
    808       "EUR:5",
    809       "deposit-refund-1",
    810       1),
    811     TALER_TESTING_cmd_deposit (
    812       "deposit-refund-insufficient-refund",
    813       "withdraw-coin-r1",
    814       0,
    815       cred.user42_payto,
    816       "{\"items\":[{\"name\":\"fruit ice cream\",\"value\":\"EUR:4\"}]}",
    817       GNUNET_TIME_UNIT_MINUTES,
    818       "EUR:4",
    819       MHD_HTTP_CONFLICT),
    820     TALER_TESTING_cmd_refund_with_id (
    821       "refund-ok-increase",
    822       MHD_HTTP_OK,
    823       "EUR:2",
    824       "deposit-refund-1",
    825       2),
    826     /**
    827      * Spend 4.99 EUR of the refunded 4.99 EUR coin (1ct gone
    828      * due to refund) (merchant would receive EUR:4.98 due to
    829      * 1 ct deposit fee) */
    830     TALER_TESTING_cmd_deposit (
    831       "deposit-refund-2",
    832       "withdraw-coin-r1",
    833       0,
    834       cred.user42_payto,
    835       "{\"items\":[{\"name\":\"more ice cream\",\"value\":\"EUR:5\"}]}",
    836       GNUNET_TIME_UNIT_ZERO,
    837       "EUR:4.99",
    838       MHD_HTTP_OK),
    839     /**
    840      * Run transfers. This will do the transfer as refund deadline
    841      * was 0
    842      */
    843     CMD_EXEC_AGGREGATOR ("run-aggregator-3"),
    844     /**
    845      * Check that deposit did run.
    846      */
    847     TALER_TESTING_cmd_check_bank_transfer (
    848       "check_bank_transfer-pre-refund",
    849       cred.exchange_url,
    850       "EUR:4.97",
    851       cred.exchange_payto,
    852       cred.user42_payto),
    853     /**
    854      * Run failing refund, as past deadline & aggregation.
    855      */
    856     TALER_TESTING_cmd_refund (
    857       "refund-fail",
    858       MHD_HTTP_GONE,
    859       "EUR:4.99",
    860       "deposit-refund-2"),
    861     TALER_TESTING_cmd_check_bank_empty ("check-empty-after-refund"),
    862     /**
    863      * Test refunded coins are never executed, even past
    864      * refund deadline
    865      */
    866     CMD_TRANSFER_TO_EXCHANGE (
    867       "create-reserve-rb",
    868       "EUR:5.01"),
    869     TALER_TESTING_cmd_check_bank_admin_transfer (
    870       "check-create-reserve-rb",
    871       "EUR:5.01",
    872       cred.user42_payto,
    873       cred.exchange_payto,
    874       "create-reserve-rb"),
    875     CMD_EXEC_WIREWATCH ("wirewatch-rb"),
    876     TALER_TESTING_cmd_withdraw_amount (
    877       "withdraw-coin-rb",
    878       "create-reserve-rb",
    879       "EUR:5",
    880       0,                                  /* age restriction off */
    881       MHD_HTTP_OK),
    882     TALER_TESTING_cmd_deposit (
    883       "deposit-refund-1b",
    884       "withdraw-coin-rb",
    885       0,
    886       cred.user42_payto,
    887       "{\"items\":[{\"name\":\"purple ice cream\",\"value\":\"EUR:5\"}]}",
    888       GNUNET_TIME_UNIT_ZERO,
    889       "EUR:5",
    890       MHD_HTTP_OK),
    891     /**
    892      * Trigger refund (before aggregator had a chance to execute
    893      * deposit, even though refund deadline was zero).
    894      */
    895     TALER_TESTING_cmd_refund (
    896       "refund-ok-fast",
    897       MHD_HTTP_OK,
    898       "EUR:5",
    899       "deposit-refund-1b"),
    900     /**
    901      * Run transfers. This will do the transfer as refund deadline
    902      * was 0, except of course because the refund succeeded, the
    903      * transfer should no longer be done.
    904      */
    905     CMD_EXEC_AGGREGATOR ("run-aggregator-3b"),
    906     /* check that aggregator didn't do anything, as expected */
    907     TALER_TESTING_cmd_check_bank_empty ("check-refund-fast-not-run"),
    908     TALER_TESTING_cmd_end ()
    909   };
    910 
    911 #if FIXME_9828
    912   struct TALER_TESTING_Command recoup[] = {
    913     /**
    914      * Fill reserve with EUR:5.01, as withdraw fee is 1 ct per
    915      * config.
    916      */
    917     CMD_TRANSFER_TO_EXCHANGE (
    918       "recoup-create-reserve-1",
    919       "EUR:15.02"),
    920     TALER_TESTING_cmd_check_bank_admin_transfer (
    921       "recoup-create-reserve-1-check",
    922       "EUR:15.02",
    923       cred.user42_payto,
    924       cred.exchange_payto,
    925       "recoup-create-reserve-1"),
    926     /**
    927      * Run wire-watch to trigger the reserve creation.
    928      */
    929     CMD_EXEC_WIREWATCH ("wirewatch-4"),
    930     /* Withdraw a 5 EUR coin, at fee of 1 ct */
    931     TALER_TESTING_cmd_withdraw_amount (
    932       "recoup-withdraw-coin-1",
    933       "recoup-create-reserve-1",
    934       "EUR:5",
    935       0,                                  /* age restriction off */
    936       MHD_HTTP_OK),
    937     /* Withdraw a 10 EUR coin, at fee of 1 ct */
    938     TALER_TESTING_cmd_withdraw_amount (
    939       "recoup-withdraw-coin-1b",
    940       "recoup-create-reserve-1",
    941       "EUR:10",
    942       0,                                  /* age restriction off */
    943       MHD_HTTP_OK),
    944     /* melt 10 EUR coin to get 5 EUR refreshed coin */
    945     TALER_TESTING_cmd_melt (
    946       "recoup-melt-coin-1b",
    947       "recoup-withdraw-coin-1b",
    948       MHD_HTTP_OK,
    949       "EUR:5",
    950       NULL),
    951     TALER_TESTING_cmd_melt_reveal (
    952       "recoup-reveal-coin-1b",
    953       "recoup-melt-coin-1b",
    954       MHD_HTTP_OK),
    955     /* Revoke both 5 EUR coins */
    956     TALER_TESTING_cmd_revoke (
    957       "revoke-0-EUR:5",
    958       MHD_HTTP_OK,
    959       "recoup-withdraw-coin-1",
    960       config_file),
    961     /* Recoup coin to reserve */
    962     TALER_TESTING_cmd_recoup (
    963       "recoup-1",
    964       MHD_HTTP_OK,
    965       "recoup-withdraw-coin-1",
    966       "EUR:5"),
    967     /* Check the money is back with the reserve */
    968     TALER_TESTING_cmd_status (
    969       "recoup-reserve-status-1",
    970       "recoup-create-reserve-1",
    971       "EUR:5.0",
    972       MHD_HTTP_OK),
    973     /* Recoup-refresh coin to 10 EUR coin */
    974     TALER_TESTING_cmd_recoup_refresh (
    975       "recoup-1b",
    976       MHD_HTTP_OK,
    977       "recoup-reveal-coin-1b",
    978       "recoup-melt-coin-1b",
    979       "EUR:5"),
    980     /* melt 10 EUR coin *again* to get 1 EUR refreshed coin */
    981     TALER_TESTING_cmd_melt (
    982       "recoup-remelt-coin-1a",
    983       "recoup-withdraw-coin-1b",
    984       MHD_HTTP_OK,
    985       "EUR:1",
    986       NULL),
    987     TALER_TESTING_cmd_melt_reveal (
    988       "recoup-reveal-coin-1a",
    989       "recoup-remelt-coin-1a",
    990       MHD_HTTP_OK),
    991     /* Try melting for more than the residual value to provoke an error */
    992     TALER_TESTING_cmd_melt (
    993       "recoup-remelt-coin-1b",
    994       "recoup-withdraw-coin-1b",
    995       MHD_HTTP_OK,
    996       "EUR:1",
    997       NULL),
    998     TALER_TESTING_cmd_melt (
    999       "recoup-remelt-coin-1c",
   1000       "recoup-withdraw-coin-1b",
   1001       MHD_HTTP_OK,
   1002       "EUR:1",
   1003       NULL),
   1004     TALER_TESTING_cmd_melt (
   1005       "recoup-remelt-coin-1d",
   1006       "recoup-withdraw-coin-1b",
   1007       MHD_HTTP_OK,
   1008       "EUR:1",
   1009       NULL),
   1010     TALER_TESTING_cmd_melt (
   1011       "recoup-remelt-coin-1e",
   1012       "recoup-withdraw-coin-1b",
   1013       MHD_HTTP_OK,
   1014       "EUR:1",
   1015       NULL),
   1016     TALER_TESTING_cmd_melt (
   1017       "recoup-remelt-coin-1f",
   1018       "recoup-withdraw-coin-1b",
   1019       MHD_HTTP_OK,
   1020       "EUR:1",
   1021       NULL),
   1022     TALER_TESTING_cmd_melt (
   1023       "recoup-remelt-coin-1g",
   1024       "recoup-withdraw-coin-1b",
   1025       MHD_HTTP_OK,
   1026       "EUR:1",
   1027       NULL),
   1028     TALER_TESTING_cmd_melt (
   1029       "recoup-remelt-coin-1h",
   1030       "recoup-withdraw-coin-1b",
   1031       MHD_HTTP_OK,
   1032       "EUR:1",
   1033       NULL),
   1034     TALER_TESTING_cmd_melt (
   1035       "recoup-remelt-coin-1i",
   1036       "recoup-withdraw-coin-1b",
   1037       MHD_HTTP_OK,
   1038       "EUR:1",
   1039       NULL),
   1040     TALER_TESTING_cmd_melt (
   1041       "recoup-remelt-coin-1b-failing",
   1042       "recoup-withdraw-coin-1b",
   1043       MHD_HTTP_CONFLICT,
   1044       "EUR:1",
   1045       NULL),
   1046     /* Re-withdraw from this reserve */
   1047     TALER_TESTING_cmd_withdraw_amount (
   1048       "recoup-withdraw-coin-2",
   1049       "recoup-create-reserve-1",
   1050       "EUR:1",
   1051       0,                                  /* age restriction off */
   1052       MHD_HTTP_OK),
   1053     /**
   1054      * This withdrawal will test the logic to create a "recoup"
   1055      * element to insert into the reserve's history.
   1056      */
   1057     TALER_TESTING_cmd_withdraw_amount (
   1058       "recoup-withdraw-coin-2-over",
   1059       "recoup-create-reserve-1",
   1060       "EUR:10",
   1061       0,                                  /* age restriction off */
   1062       MHD_HTTP_CONFLICT),
   1063     TALER_TESTING_cmd_status (
   1064       "recoup-reserve-status-2",
   1065       "recoup-create-reserve-1",
   1066       "EUR:3.99",
   1067       MHD_HTTP_OK),
   1068     /* These commands should close the reserve because
   1069      * the aggregator is given a config file that overrides
   1070      * the reserve expiration time (making it now-ish) */
   1071     CMD_TRANSFER_TO_EXCHANGE ("short-lived-reserve",
   1072                               "EUR:5.01"),
   1073     TALER_TESTING_cmd_check_bank_admin_transfer (
   1074       "check-short-lived-reserve",
   1075       "EUR:5.01",
   1076       cred.user42_payto,
   1077       cred.exchange_payto,
   1078       "short-lived-reserve"),
   1079     TALER_TESTING_cmd_exec_wirewatch2 (
   1080       "short-lived-aggregation",
   1081       config_file_expire_reserve_now,
   1082       "exchange-account-2"),
   1083     TALER_TESTING_cmd_exec_closer (
   1084       "close-reserves",
   1085       config_file_expire_reserve_now,
   1086       "EUR:5",
   1087       "EUR:0.01",
   1088       "short-lived-reserve"),
   1089     TALER_TESTING_cmd_exec_transfer (
   1090       "close-reserves-transfer",
   1091       config_file_expire_reserve_now),
   1092 
   1093     TALER_TESTING_cmd_status (
   1094       "short-lived-status",
   1095       "short-lived-reserve",
   1096       "EUR:0",
   1097       MHD_HTTP_OK),
   1098     TALER_TESTING_cmd_withdraw_amount (
   1099       "expired-withdraw",
   1100       "short-lived-reserve",
   1101       "EUR:1",
   1102       0,                                  /* age restriction off */
   1103       MHD_HTTP_CONFLICT),
   1104     TALER_TESTING_cmd_check_bank_transfer (
   1105       "check_bank_short-lived_reimburse",
   1106       cred.exchange_url,
   1107       "EUR:5",
   1108       cred.exchange_payto,
   1109       cred.user42_payto),
   1110     /* Fill reserve with EUR:2.02, as withdraw fee is 1 ct per
   1111      * config, then withdraw two coin, partially spend one, and
   1112      * then have the rest paid back.  Check deposit of other coin
   1113      * fails.  Do not use EUR:5 here as the EUR:5 coin was
   1114      * revoked and we did not bother to create a new one... */
   1115     CMD_TRANSFER_TO_EXCHANGE ("recoup-create-reserve-2",
   1116                               "EUR:2.02"),
   1117     TALER_TESTING_cmd_check_bank_admin_transfer (
   1118       "ck-recoup-create-reserve-2",
   1119       "EUR:2.02",
   1120       cred.user42_payto,
   1121       cred.exchange_payto,
   1122       "recoup-create-reserve-2"),
   1123     /* Make previous command effective. */
   1124     CMD_EXEC_WIREWATCH ("wirewatch-5"),
   1125     /* Withdraw a 1 EUR coin, at fee of 1 ct */
   1126     TALER_TESTING_cmd_withdraw_amount (
   1127       "recoup-withdraw-coin-2a",
   1128       "recoup-create-reserve-2",
   1129       "EUR:1",
   1130       0,                                  /* age restriction off */
   1131       MHD_HTTP_OK),
   1132     /* Withdraw a 1 EUR coin, at fee of 1 ct */
   1133     TALER_TESTING_cmd_withdraw_amount (
   1134       "recoup-withdraw-coin-2b",
   1135       "recoup-create-reserve-2",
   1136       "EUR:1",
   1137       0,                                  /* age restriction off */
   1138       MHD_HTTP_OK),
   1139     TALER_TESTING_cmd_deposit (
   1140       "recoup-deposit-partial",
   1141       "recoup-withdraw-coin-2a",
   1142       0,
   1143       cred.user42_payto,
   1144       "{\"items\":[{\"name\":\"more ice cream\",\"value\":1}]}",
   1145       GNUNET_TIME_UNIT_ZERO,
   1146       "EUR:0.5",
   1147       MHD_HTTP_OK),
   1148     TALER_TESTING_cmd_revoke (
   1149       "revoke-1-EUR:1",
   1150       MHD_HTTP_OK,
   1151       "recoup-withdraw-coin-2a",
   1152       config_file),
   1153     /* Check recoup is failing for the coin with the reused coin key
   1154        (fails either because of denomination conflict (RSA) or
   1155        double-spending (CS))*/
   1156     TALER_TESTING_cmd_recoup (
   1157       "recoup-2x",
   1158       MHD_HTTP_CONFLICT,
   1159       "withdraw-coin-1x",
   1160       "EUR:1"),
   1161     TALER_TESTING_cmd_recoup (
   1162       "recoup-2",
   1163       MHD_HTTP_OK,
   1164       "recoup-withdraw-coin-2a",
   1165       "EUR:0.5"),
   1166     /* Idempotency of recoup (withdrawal variant) */
   1167     TALER_TESTING_cmd_recoup (
   1168       "recoup-2b",
   1169       MHD_HTTP_OK,
   1170       "recoup-withdraw-coin-2a",
   1171       "EUR:0.5"),
   1172     TALER_TESTING_cmd_deposit (
   1173       "recoup-deposit-revoked",
   1174       "recoup-withdraw-coin-2b",
   1175       0,
   1176       cred.user42_payto,
   1177       "{\"items\":[{\"name\":\"gnu ice cream\",\"value\":1}]}",
   1178       GNUNET_TIME_UNIT_ZERO,
   1179       "EUR:1",
   1180       MHD_HTTP_GONE),
   1181     /* Test deposit fails after recoup, with proof in recoup */
   1182 
   1183     /* Note that, the exchange will never return the coin's transaction
   1184      * history with recoup data, as we get a 410 on the DK! */
   1185     TALER_TESTING_cmd_deposit (
   1186       "recoup-deposit-partial-after-recoup",
   1187       "recoup-withdraw-coin-2a",
   1188       0,
   1189       cred.user42_payto,
   1190       "{\"items\":[{\"name\":\"extra ice cream\",\"value\":1}]}",
   1191       GNUNET_TIME_UNIT_ZERO,
   1192       "EUR:0.5",
   1193       MHD_HTTP_GONE),
   1194     /* Test that revoked coins cannot be withdrawn */
   1195     CMD_TRANSFER_TO_EXCHANGE (
   1196       "recoup-create-reserve-3",
   1197       "EUR:1.01"),
   1198     TALER_TESTING_cmd_check_bank_admin_transfer (
   1199       "check-recoup-create-reserve-3",
   1200       "EUR:1.01",
   1201       cred.user42_payto,
   1202       cred.exchange_payto,
   1203       "recoup-create-reserve-3"),
   1204     CMD_EXEC_WIREWATCH ("wirewatch-6"),
   1205     TALER_TESTING_cmd_withdraw_amount (
   1206       "recoup-withdraw-coin-3-revoked",
   1207       "recoup-create-reserve-3",
   1208       "EUR:1",
   1209       0,                                  /* age restriction off */
   1210       MHD_HTTP_GONE),
   1211     /* check that we are empty before the rejection test */
   1212     TALER_TESTING_cmd_check_bank_empty ("check-empty-again"),
   1213 
   1214     TALER_TESTING_cmd_end ()
   1215   };
   1216 #endif
   1217 
   1218   /**
   1219    * Test batch withdrawal plus spending.
   1220    */
   1221   struct TALER_TESTING_Command batch_withdraw[] = {
   1222     /**
   1223      * Move money to the exchange's bank account.
   1224      */
   1225     CMD_TRANSFER_TO_EXCHANGE (
   1226       "create-batch-reserve-1",
   1227       "EUR:6.03"),
   1228     TALER_TESTING_cmd_reserve_poll (
   1229       "poll-batch-reserve-1",
   1230       "create-batch-reserve-1",
   1231       "EUR:6.03",
   1232       GNUNET_TIME_UNIT_MINUTES,
   1233       MHD_HTTP_OK),
   1234     TALER_TESTING_cmd_check_bank_admin_transfer (
   1235       "check-create-batch-reserve-1",
   1236       "EUR:6.03",
   1237       cred.user42_payto,
   1238       cred.exchange_payto,
   1239       "create-batch-reserve-1"),
   1240     /*
   1241      * Make a reserve exist, according to the previous
   1242      * transfer.
   1243      */
   1244     CMD_EXEC_WIREWATCH ("wirewatch-batch-1"),
   1245     TALER_TESTING_cmd_reserve_poll_finish (
   1246       "finish-poll-batch-reserve-1",
   1247       GNUNET_TIME_UNIT_SECONDS,
   1248       "poll-batch-reserve-1"),
   1249     /**
   1250      * Withdraw EUR:5 AND EUR:1.
   1251      */
   1252     TALER_TESTING_cmd_batch_withdraw (
   1253       "batch-withdraw-coin-1",
   1254       "create-batch-reserve-1",
   1255       MHD_HTTP_OK,
   1256       "EUR:5",
   1257       "EUR:1",
   1258       NULL),
   1259     /**
   1260      * Check the reserve is (almost) depleted.
   1261      */
   1262     TALER_TESTING_cmd_status (
   1263       "status-batch-1",
   1264       "create-batch-reserve-1",
   1265       "EUR:0.01",
   1266       MHD_HTTP_OK),
   1267     TALER_TESTING_cmd_reserve_history (
   1268       "history-batch-1",
   1269       "create-batch-reserve-1",
   1270       "EUR:0.01",
   1271       MHD_HTTP_OK),
   1272     /**
   1273      * Spend the coins.
   1274      */
   1275     TALER_TESTING_cmd_batch_deposit (
   1276       "batch-deposit-1",
   1277       cred.user42_payto,
   1278       "{\"items\":[{\"name\":\"final ice cream\",\"value\":5}]}",
   1279       GNUNET_TIME_UNIT_ZERO,
   1280       MHD_HTTP_OK,
   1281       "batch-withdraw-coin-1#0",
   1282       "EUR:5",
   1283       "batch-withdraw-coin-1#1",
   1284       "EUR:1",
   1285       NULL),
   1286     TALER_TESTING_cmd_coin_history (
   1287       "coin-history-batch-1",
   1288       "batch-withdraw-coin-1#0",
   1289       "EUR:0.0",
   1290       MHD_HTTP_OK),
   1291     TALER_TESTING_cmd_end ()
   1292   };
   1293 
   1294 
   1295 #define RESERVE_OPEN_CLOSE_CHUNK 4
   1296 #define RESERVE_OPEN_CLOSE_ITERATIONS 3
   1297 
   1298   struct TALER_TESTING_Command reserve_open_close[(RESERVE_OPEN_CLOSE_ITERATIONS
   1299                                                    * RESERVE_OPEN_CLOSE_CHUNK)
   1300                                                   + 1];
   1301 
   1302   (void) cls;
   1303   for (unsigned int i = 0;
   1304        i < RESERVE_OPEN_CLOSE_ITERATIONS;
   1305        i++)
   1306   {
   1307     reserve_open_close[(i * RESERVE_OPEN_CLOSE_CHUNK) + 0]
   1308       = CMD_TRANSFER_TO_EXCHANGE ("reserve-open-close-key",
   1309                                   "EUR:20");
   1310     reserve_open_close[(i * RESERVE_OPEN_CLOSE_CHUNK) + 1]
   1311       = TALER_TESTING_cmd_exec_wirewatch2 ("reserve-open-close-wirewatch",
   1312                                            config_file_expire_reserve_now,
   1313                                            "exchange-account-2");
   1314     reserve_open_close[(i * RESERVE_OPEN_CLOSE_CHUNK) + 2]
   1315       = TALER_TESTING_cmd_exec_closer ("reserve-open-close-aggregation",
   1316                                        config_file_expire_reserve_now,
   1317                                        "EUR:19.99",
   1318                                        "EUR:0.01",
   1319                                        "reserve-open-close-key");
   1320     reserve_open_close[(i * RESERVE_OPEN_CLOSE_CHUNK) + 3]
   1321       = TALER_TESTING_cmd_status ("reserve-open-close-status",
   1322                                   "reserve-open-close-key",
   1323                                   "EUR:0",
   1324                                   MHD_HTTP_OK);
   1325   }
   1326   reserve_open_close[RESERVE_OPEN_CLOSE_ITERATIONS * RESERVE_OPEN_CLOSE_CHUNK]
   1327     = TALER_TESTING_cmd_end ();
   1328 
   1329   {
   1330     struct TALER_TESTING_Command commands[] = {
   1331       TALER_TESTING_cmd_run_fakebank ("run-fakebank",
   1332                                       cred.cfg,
   1333                                       "exchange-account-2"),
   1334       TALER_TESTING_cmd_system_start ("start-taler",
   1335                                       config_file,
   1336                                       "-e",
   1337                                       NULL),
   1338       TALER_TESTING_cmd_get_exchange ("get-exchange",
   1339                                       cred.cfg,
   1340                                       NULL,
   1341                                       true,
   1342                                       true),
   1343       TALER_TESTING_cmd_batch ("withdraw",
   1344                                withdraw),
   1345       TALER_TESTING_cmd_batch ("spend",
   1346                                spend),
   1347       TALER_TESTING_cmd_batch ("refresh",
   1348                                refresh),
   1349       TALER_TESTING_cmd_batch ("withdraw-age",
   1350                                withdraw_age),
   1351       TALER_TESTING_cmd_batch ("spend-age",
   1352                                spend_age),
   1353       TALER_TESTING_cmd_batch ("refresh-age",
   1354                                refresh_age),
   1355       TALER_TESTING_cmd_batch ("track",
   1356                                track),
   1357       TALER_TESTING_cmd_batch ("unaggregation",
   1358                                unaggregation),
   1359       TALER_TESTING_cmd_batch ("aggregation",
   1360                                aggregation),
   1361       TALER_TESTING_cmd_batch ("refund",
   1362                                refund),
   1363       TALER_TESTING_cmd_batch ("batch-withdraw",
   1364                                batch_withdraw),
   1365 #if FIXME_9828
   1366       TALER_TESTING_cmd_batch ("recoup",
   1367                                recoup),
   1368 #endif
   1369       TALER_TESTING_cmd_batch ("reserve-open-close",
   1370                                reserve_open_close),
   1371       /* End the suite. */
   1372       TALER_TESTING_cmd_end ()
   1373     };
   1374 
   1375     TALER_TESTING_run (is,
   1376                        commands);
   1377   }
   1378 }
   1379 
   1380 
   1381 int
   1382 main (int argc,
   1383       char *const *argv)
   1384 {
   1385   (void) argc;
   1386   {
   1387     char *cipher;
   1388 
   1389     cipher = GNUNET_STRINGS_get_suffix_from_binary_name (argv[0]);
   1390     GNUNET_assert (NULL != cipher);
   1391     uses_cs = (0 == strcmp (cipher,
   1392                             "cs"));
   1393     GNUNET_asprintf (&config_file,
   1394                      "test_exchange_api-%s.conf",
   1395                      cipher);
   1396     GNUNET_asprintf (&config_file_expire_reserve_now,
   1397                      "test_exchange_api_expire_reserve_now-%s.conf",
   1398                      cipher);
   1399     GNUNET_free (cipher);
   1400   }
   1401   return TALER_TESTING_main (argv,
   1402                              "INFO",
   1403                              config_file,
   1404                              "exchange-account-2",
   1405                              TALER_TESTING_BS_FAKEBANK,
   1406                              &cred,
   1407                              &run,
   1408                              NULL);
   1409 }
   1410 
   1411 
   1412 /* end of test_exchange_api.c */