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 (44957B)


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