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


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