merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

test_merchant_api.c (191372B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2014-2023 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 src/testing/test_merchant_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 "platform.h"
     27 #include <gnunet/gnunet_time_lib.h>
     28 #include <taler/taler_util.h>
     29 #include <taler/taler_signatures.h>
     30 #include <taler/taler_exchange_service.h>
     31 #include <taler/taler_json_lib.h>
     32 #include <gnunet/gnunet_util_lib.h>
     33 #include <gnunet/gnunet_testing_lib.h>
     34 #include <microhttpd.h>
     35 #include <taler/taler_bank_service.h>
     36 #include <taler/taler_fakebank_lib.h>
     37 #include <taler/taler_testing_lib.h>
     38 #include <taler/taler_error_codes.h>
     39 #include "taler/taler_merchant_util.h"
     40 #include "taler/taler_merchant_testing_lib.h"
     41 #include <donau/donau_testing_lib.h>
     42 
     43 
     44 /**
     45  * The 'poll-orders-conclude-1' and other 'conclude'
     46  * commands should NOT wait for this timeout!
     47  */
     48 #define POLL_ORDER_TIMEOUT \
     49         GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
     50 
     51 /**
     52  * The 'poll-orders-conclude-1x' and other 'conclude'
     53  * commands that should (!) wait for this timeout! Hence,
     54  * here we use a short value!
     55  */
     56 #define POLL_ORDER_SHORT_TIMEOUT \
     57         GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2)
     58 
     59 /**
     60  * Configuration file we use.  One (big) configuration is used
     61  * for the various components for this test.
     62  */
     63 static char *config_file;
     64 
     65 /**
     66  * Exchange base URL.  Could also be taken from config.
     67  */
     68 #define EXCHANGE_URL "http://localhost:8081/"
     69 
     70 /**
     71  * Payto URI of the customer (payer).
     72  */
     73 static struct TALER_FullPayto payer_payto;
     74 
     75 /**
     76  * Payto URI of the exchange (escrow account).
     77  */
     78 static struct TALER_FullPayto exchange_payto;
     79 
     80 /**
     81  * Payto URI of the merchant (receiver).
     82  */
     83 static struct TALER_FullPayto merchant_payto;
     84 
     85 /**
     86  * Credentials for the test.
     87  */
     88 static struct TALER_TESTING_Credentials cred;
     89 
     90 /**
     91  * Merchant base URL.
     92  */
     93 static const char *merchant_url;
     94 
     95 /**
     96  * Merchant instance "i1a" base URL.
     97  */
     98 static char *merchant_url_i1a;
     99 
    100 /**
    101  * Account number of the exchange at the bank.
    102  */
    103 #define EXCHANGE_ACCOUNT_NAME "2"
    104 
    105 /**
    106  * Account number of some user.
    107  */
    108 #define USER_ACCOUNT_NAME "62"
    109 
    110 /**
    111  * Account number of some other user.
    112  */
    113 #define USER_ACCOUNT_NAME2 "63"
    114 
    115 /**
    116  * Account number used by the merchant
    117  */
    118 #define MERCHANT_ACCOUNT_NAME "3"
    119 
    120 static const char *order_1_transfers[] = {
    121   "post-transfer-1",
    122   NULL
    123 };
    124 
    125 static const char *order_1_forgets_1[] = {
    126   "forget-1",
    127   NULL
    128 };
    129 
    130 static const char *order_1_forgets_2[] = {
    131   "forget-1",
    132   "forget-order-array-elem",
    133   NULL
    134 };
    135 
    136 static const char *order_1_forgets_3[] = {
    137   "forget-1",
    138   "forget-order-array-elem",
    139   "forget-order-array-wc",
    140   NULL
    141 };
    142 
    143 static const struct TALER_TESTING_ProductUnitExpectations
    144   expect_unicorn_defaults = {
    145   .have_unit_allow_fraction = true,
    146   .unit_allow_fraction = true,
    147   .have_unit_precision_level = true,
    148   .unit_precision_level = 1
    149 };
    150 
    151 static const struct TALER_TESTING_ProductUnitExpectations
    152   expect_unicorn_patched = {
    153   .have_unit_allow_fraction = true,
    154   .unit_allow_fraction = false,
    155   .have_unit_precision_level = true,
    156   .unit_precision_level = 0
    157 };
    158 
    159 /**
    160  * Build an array of selected product IDs.
    161  *
    162  * @param first first product id
    163  * @param second second product id or NULL
    164  * @return JSON array of product ids
    165  */
    166 static json_t *
    167 make_selected_products (const char *first,
    168                         const char *second)
    169 {
    170   json_t *arr;
    171 
    172   arr = json_array ();
    173   GNUNET_assert (NULL != arr);
    174   if (NULL != first)
    175     GNUNET_assert (0 ==
    176                    json_array_append_new (arr,
    177                                           json_string (first)));
    178   if (NULL != second)
    179     GNUNET_assert (0 ==
    180                    json_array_append_new (arr,
    181                                           json_string (second)));
    182   return arr;
    183 }
    184 
    185 
    186 /**
    187  * Build an array of selected category IDs.
    188  *
    189  * @param first first category id
    190  * @param second second category id or 0
    191  * @return JSON array of category ids
    192  */
    193 static json_t *
    194 make_selected_categories (uint64_t first,
    195                           uint64_t second)
    196 {
    197   json_t *arr;
    198 
    199   arr = json_array ();
    200   GNUNET_assert (NULL != arr);
    201   if (0 != first)
    202     GNUNET_assert (0 ==
    203                    json_array_append_new (arr,
    204                                           json_integer (first)));
    205   if (0 != second)
    206     GNUNET_assert (0 ==
    207                    json_array_append_new (arr,
    208                                           json_integer (second)));
    209   return arr;
    210 }
    211 
    212 
    213 /**
    214  * Build an inventory selection array.
    215  *
    216  * @param first_id first product id
    217  * @param first_qty first quantity
    218  * @param second_id second product id or NULL
    219  * @param second_qty second quantity or NULL
    220  * @return JSON array of inventory selections
    221  */
    222 static json_t *
    223 make_inventory_selection (const char *first_id,
    224                           const char *first_qty,
    225                           const char *second_id,
    226                           const char *second_qty)
    227 {
    228   json_t *arr;
    229 
    230   arr = json_array ();
    231   GNUNET_assert (NULL != arr);
    232   if (NULL != first_id)
    233     GNUNET_assert (0 ==
    234                    json_array_append_new (
    235                      arr,
    236                      GNUNET_JSON_PACK (
    237                        GNUNET_JSON_pack_string ("product_id",
    238                                                 first_id),
    239                        GNUNET_JSON_pack_string ("quantity",
    240                                                 first_qty))));
    241   if (NULL != second_id)
    242     GNUNET_assert (0 ==
    243                    json_array_append_new (
    244                      arr,
    245                      GNUNET_JSON_PACK (
    246                        GNUNET_JSON_pack_string ("product_id",
    247                                                 second_id),
    248                        GNUNET_JSON_pack_string ("quantity",
    249                                                 second_qty))));
    250   return arr;
    251 }
    252 
    253 
    254 /**
    255  * Execute the taler-merchant-webhook command with
    256  * our configuration file.
    257  *
    258  * @param label label to use for the command.
    259  */
    260 static struct TALER_TESTING_Command
    261 cmd_webhook (const char *label)
    262 {
    263   return TALER_TESTING_cmd_webhook (label, config_file);
    264 }
    265 
    266 
    267 /**
    268  * Execute the taler-exchange-wirewatch command with
    269  * our configuration file.
    270  *
    271  * @param label label to use for the command.
    272  */
    273 static struct TALER_TESTING_Command
    274 cmd_exec_wirewatch (const char *label)
    275 {
    276   return TALER_TESTING_cmd_exec_wirewatch (label,
    277                                            config_file);
    278 }
    279 
    280 
    281 /**
    282  * Execute the taler-exchange-aggregator, closer and transfer commands with
    283  * our configuration file.
    284  *
    285  * @param label label to use for the command.
    286  */
    287 #define CMD_EXEC_AGGREGATOR(label) \
    288         TALER_TESTING_cmd_exec_aggregator (label "-aggregator", config_file), \
    289         TALER_TESTING_cmd_exec_transfer (label "-transfer", config_file)
    290 
    291 
    292 /**
    293  * Run wire transfer of funds from some user's account to the
    294  * exchange.
    295  *
    296  * @param label label to use for the command.
    297  * @param amount amount to transfer, i.e. "EUR:1"
    298  * @param url exchange_url
    299  */
    300 static struct TALER_TESTING_Command
    301 cmd_transfer_to_exchange (const char *label,
    302                           const char *amount)
    303 {
    304   return TALER_TESTING_cmd_admin_add_incoming (label,
    305                                                amount,
    306                                                &cred.ba,
    307                                                payer_payto);
    308 }
    309 
    310 
    311 /**
    312  * Grants of the fountain used in the token tests (DD 98): the
    313  * "subscription-1" family may be withdrawn from, at most 3 tokens
    314  * per issue-key validity period, for the current and the next slot.
    315  */
    316 static const struct TALER_MERCHANT_FountainGrant fountain_grants[] = {
    317   {
    318     .token_family_slug = "subscription-1",
    319     .tokens_per_period_limit = 3,
    320     .tokens_per_period_stash = 2,
    321     .key_window_size = 1
    322   }
    323 };
    324 
    325 
    326 /**
    327  * Grants referring to a token family that the fountain does not
    328  * grant; used to check that withdrawing from it is refused.
    329  */
    330 static const struct TALER_MERCHANT_FountainGrant fountain_grants_other[] = {
    331   {
    332     .token_family_slug = "subscription-upcoming",
    333     .tokens_per_period_limit = 1,
    334     .tokens_per_period_stash = 1,
    335     .key_window_size = 0
    336   }
    337 };
    338 
    339 
    340 /**
    341  * Main function that will tell the interpreter what commands to
    342  * run.
    343  *
    344  * @param cls closure
    345  */
    346 static void
    347 run (void *cls,
    348      struct TALER_TESTING_Interpreter *is)
    349 {
    350   struct TALER_TESTING_Command get_private_order_id[] = {
    351     TALER_TESTING_cmd_merchant_post_instances (
    352       "instance-create-admin",
    353       merchant_url,
    354       "admin",
    355       MHD_HTTP_NO_CONTENT),
    356     TALER_TESTING_cmd_merchant_kyc_get (
    357       "instance-create-kyc-no-accounts",
    358       merchant_url,
    359       NULL,
    360       NULL,
    361       EXCHANGE_URL,
    362       TALER_EXCHANGE_KLPT_NONE,
    363       MHD_HTTP_NO_CONTENT,
    364       false),
    365     TALER_TESTING_cmd_merchant_post_account (
    366       "instance-create-default-account",
    367       merchant_url,
    368       merchant_payto,
    369       NULL, NULL,
    370       MHD_HTTP_OK),
    371     TALER_TESTING_cmd_merchant_kyc_get (
    372       "instance-create-kyc-0",
    373       merchant_url,
    374       NULL,
    375       NULL,
    376       EXCHANGE_URL,
    377       TALER_EXCHANGE_KLPT_NONE,
    378       MHD_HTTP_OK,
    379       true),
    380     TALER_TESTING_cmd_merchant_post_orders_no_claim (
    381       "create-proposal-bad-currency",
    382       merchant_url,
    383       MHD_HTTP_CONFLICT,
    384       "4",
    385       GNUNET_TIME_UNIT_ZERO_TS,
    386       GNUNET_TIME_UNIT_FOREVER_TS,
    387       "XXX:5.0"),
    388     TALER_TESTING_cmd_merchant_post_orders_no_claim (
    389       "create-proposal-4",
    390       merchant_url,
    391       MHD_HTTP_OK,
    392       "4",
    393       GNUNET_TIME_UNIT_ZERO_TS,
    394       GNUNET_TIME_UNIT_FOREVER_TS,
    395       "EUR:5.0"),
    396     TALER_TESTING_cmd_merchant_get_order (
    397       "get-order-4",
    398       merchant_url,
    399       "create-proposal-4",
    400       TALER_MERCHANT_OSC_UNPAID,
    401       false,
    402       MHD_HTTP_OK,
    403       NULL),
    404     TALER_TESTING_cmd_merchant_delete_order (
    405       "delete-order-4",
    406       merchant_url,
    407       "4",
    408       MHD_HTTP_NO_CONTENT),
    409     TALER_TESTING_cmd_merchant_purge_instance (
    410       "purge-admin",
    411       merchant_url,
    412       "admin",
    413       MHD_HTTP_NO_CONTENT),
    414     TALER_TESTING_cmd_end ()
    415   };
    416 
    417   struct TALER_TESTING_Command pay[] = {
    418     /**
    419      * Move money to the exchange's bank account.
    420      */
    421     cmd_transfer_to_exchange ("create-reserve-1",
    422                               "EUR:10.02"),
    423     /**
    424      * Make a reserve exist, according to the previous transfer.
    425      */
    426     cmd_exec_wirewatch ("wirewatch-1"),
    427     TALER_TESTING_cmd_check_bank_admin_transfer ("check_bank_transfer-2",
    428                                                  "EUR:10.02",
    429                                                  payer_payto,
    430                                                  exchange_payto,
    431                                                  "create-reserve-1"),
    432     TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1",
    433                                        "create-reserve-1",
    434                                        "EUR:5",
    435                                        0,
    436                                        MHD_HTTP_OK),
    437     TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-2",
    438                                        "create-reserve-1",
    439                                        "EUR:5",
    440                                        0,
    441                                        MHD_HTTP_OK),
    442     TALER_TESTING_cmd_merchant_get_orders ("get-orders-empty",
    443                                            merchant_url,
    444                                            MHD_HTTP_OK,
    445                                            NULL),
    446     /**
    447      * Check the reserve is depleted.
    448      */
    449     TALER_TESTING_cmd_status ("withdraw-status-1",
    450                               "create-reserve-1",
    451                               "EUR:0",
    452                               MHD_HTTP_OK),
    453     TALER_TESTING_cmd_merchant_delete_order ("delete-order-nx",
    454                                              merchant_url,
    455                                              "1",
    456                                              MHD_HTTP_NOT_FOUND),
    457     TALER_TESTING_cmd_poll_orders_start ("poll-orders-1-start",
    458                                          merchant_url,
    459                                          POLL_ORDER_TIMEOUT),
    460     TALER_TESTING_cmd_merchant_claim_order ("claim-order-nx",
    461                                             merchant_url,
    462                                             MHD_HTTP_NOT_FOUND,
    463                                             NULL,
    464                                             "1"),
    465     TALER_TESTING_cmd_merchant_post_orders2 ("create-proposal-1",
    466                                              cred.cfg,
    467                                              merchant_url,
    468                                              MHD_HTTP_OK,
    469                                              "1",
    470                                              GNUNET_TIME_UNIT_ZERO_TS,
    471                                              GNUNET_TIME_UNIT_FOREVER_TS,
    472                                              true,
    473                                              "EUR:5.0",
    474                                              "x-taler-bank",
    475                                              "",
    476                                              "",
    477                                              NULL),
    478     TALER_TESTING_cmd_merchant_post_webhooks ("post-webhooks-pay-w1",
    479                                               merchant_url,
    480                                               "webhook-pay-1",
    481                                               "pay",
    482                                               MHD_HTTP_NO_CONTENT),
    483     TALER_TESTING_cmd_merchant_post_webhooks2 ("post-webhooks-settled-w1",
    484                                                merchant_url,
    485                                                "webhook-settled-1",
    486                                                "order_settled",
    487                                                "http://localhost:12345/",
    488                                                "POST",
    489                                                "Taler-test-header: settled",
    490                                                "order-settled",
    491                                                MHD_HTTP_NO_CONTENT),
    492     TALER_TESTING_cmd_testserver ("launch-http-server-for-webhooks",
    493                                   12345),
    494     TALER_TESTING_cmd_merchant_post_orders2 ("create-proposal-1-idem",
    495                                              cred.cfg,
    496                                              merchant_url,
    497                                              MHD_HTTP_OK,
    498                                              "1",
    499                                              GNUNET_TIME_UNIT_ZERO_TS,
    500                                              GNUNET_TIME_UNIT_FOREVER_TS,
    501                                              true,
    502                                              "EUR:5.0",
    503                                              "x-taler-bank",
    504                                              "",
    505                                              "",
    506                                              "create-proposal-1"),
    507     TALER_TESTING_cmd_merchant_post_orders2 ("create-proposal-1x",
    508                                              cred.cfg,
    509                                              merchant_url,
    510                                              MHD_HTTP_OK,
    511                                              "1x",
    512                                              GNUNET_TIME_UNIT_ZERO_TS,
    513                                              GNUNET_TIME_UNIT_FOREVER_TS,
    514                                              true,
    515                                              "EUR:5.0",
    516                                              "x-taler-bank",
    517                                              "",
    518                                              "",
    519                                              NULL),
    520     TALER_TESTING_cmd_merchant_claim_order ("reclaim-1",
    521                                             merchant_url,
    522                                             MHD_HTTP_OK,
    523                                             "create-proposal-1",
    524                                             NULL),
    525     TALER_TESTING_cmd_merchant_claim_order ("reclaim-1-bad-nonce",
    526                                             merchant_url,
    527                                             MHD_HTTP_CONFLICT,
    528                                             NULL,
    529                                             "1"),
    530     TALER_TESTING_cmd_merchant_claim_order ("reclaim-1x",
    531                                             merchant_url,
    532                                             MHD_HTTP_OK,
    533                                             "create-proposal-1x",
    534                                             NULL),
    535     /* A claimed order is owned by the wallet that claimed it, so it
    536        may only be deleted with an explicit force option. */
    537     TALER_TESTING_cmd_merchant_post_orders_no_claim (
    538       "create-proposal-claimed-del",
    539       merchant_url,
    540       MHD_HTTP_OK,
    541       "claimed-del",
    542       GNUNET_TIME_UNIT_ZERO_TS,
    543       GNUNET_TIME_UNIT_FOREVER_TS,
    544       "EUR:5.0"),
    545     /* deleting it now, while still unclaimed, would simply work */
    546     TALER_TESTING_cmd_merchant_claim_order ("claim-claimed-del",
    547                                             merchant_url,
    548                                             MHD_HTTP_OK,
    549                                             "create-proposal-claimed-del",
    550                                             NULL),
    551     TALER_TESTING_cmd_merchant_delete_order2 ("delete-claimed-del-noforce",
    552                                               merchant_url,
    553                                               "claimed-del",
    554                                               false,
    555                                               MHD_HTTP_CONFLICT),
    556     TALER_TESTING_cmd_merchant_delete_order2 ("delete-claimed-del-force",
    557                                               merchant_url,
    558                                               "claimed-del",
    559                                               true, /* force flag */
    560                                               MHD_HTTP_NO_CONTENT),
    561     TALER_TESTING_cmd_merchant_post_orders ("create-proposal-1-pre-exists",
    562                                             cred.cfg,
    563                                             merchant_url,
    564                                             MHD_HTTP_CONFLICT,
    565                                             "1",
    566                                             GNUNET_TIME_UNIT_ZERO_TS,
    567                                             GNUNET_TIME_UNIT_FOREVER_TS,
    568                                             "EUR:5.0"),
    569     TALER_TESTING_cmd_poll_orders_conclude ("poll-orders-1-conclude",
    570                                             MHD_HTTP_OK,
    571                                             "poll-orders-1-start"),
    572     TALER_TESTING_cmd_merchant_get_orders ("get-orders-1",
    573                                            merchant_url,
    574                                            MHD_HTTP_OK,
    575                                            "create-proposal-1x",
    576                                            "create-proposal-1",
    577                                            NULL),
    578     TALER_TESTING_cmd_wallet_get_order ("get-order-wallet-1",
    579                                         merchant_url,
    580                                         "create-proposal-1",
    581                                         false,
    582                                         false,
    583                                         false,
    584                                         MHD_HTTP_PAYMENT_REQUIRED),
    585     TALER_TESTING_cmd_merchant_get_order ("get-order-merchant-1",
    586                                           merchant_url,
    587                                           "create-proposal-1",
    588                                           TALER_MERCHANT_OSC_CLAIMED,
    589                                           false,
    590                                           MHD_HTTP_OK,
    591                                           NULL),
    592     TALER_TESTING_cmd_wallet_poll_order_start ("poll-order-wallet-start-1",
    593                                                merchant_url,
    594                                                "create-proposal-1",
    595                                                POLL_ORDER_TIMEOUT,
    596                                                NULL),
    597     TALER_TESTING_cmd_wallet_poll_order_start2 ("poll-order-wallet-start-1x",
    598                                                 merchant_url,
    599                                                 "create-proposal-1x",
    600                                                 POLL_ORDER_SHORT_TIMEOUT,
    601                                                 NULL, /* no refund */
    602                                                 "session-0"),
    603     TALER_TESTING_cmd_poll_order_start ("poll-order-merchant-1-start",
    604                                         merchant_url,
    605                                         "1",
    606                                         POLL_ORDER_TIMEOUT),
    607     TALER_TESTING_cmd_merchant_pay_order ("deposit-simple",
    608                                           merchant_url,
    609                                           MHD_HTTP_OK,
    610                                           "create-proposal-1",
    611                                           "withdraw-coin-1",
    612                                           "EUR:5",
    613                                           "EUR:4.99",
    614                                           "session-0"),
    615     TALER_TESTING_cmd_poll_order_conclude ("poll-order-merchant-1-conclude",
    616                                            MHD_HTTP_OK,
    617                                            "poll-order-merchant-1-start"),
    618     TALER_TESTING_cmd_wallet_poll_order_conclude ("poll-order-1-conclude",
    619                                                   MHD_HTTP_OK,
    620                                                   NULL,
    621                                                   "poll-order-wallet-start-1"),
    622     /* Check for webhook */
    623     cmd_webhook ("pending-webhooks-pay-w1"),
    624     /* Check webhook did anything: have a command that inspects traits of the testserver
    625        and check if the traits have the right values set! */
    626     TALER_TESTING_cmd_checkserver ("check-http-server-for-webhooks",
    627                                    "launch-http-server-for-webhooks",
    628                                    0),
    629     /* Here we expect to run into a timeout, as we do not pay this one */
    630     TALER_TESTING_cmd_wallet_poll_order_conclude2 ("poll-order-1x-conclude",
    631                                                    MHD_HTTP_PAYMENT_REQUIRED,
    632                                                    NULL,
    633                                                    "poll-order-wallet-start-1x",
    634                                                    "1"),
    635     TALER_TESTING_cmd_merchant_post_orders_paid ("verify-order-1-paid",
    636                                                  merchant_url,
    637                                                  "deposit-simple",
    638                                                  "session-1",
    639                                                  MHD_HTTP_OK),
    640     TALER_TESTING_cmd_wallet_get_order ("get-order-wallet-1-2",
    641                                         merchant_url,
    642                                         "create-proposal-1",
    643                                         true,
    644                                         false,
    645                                         false,
    646                                         MHD_HTTP_OK),
    647     TALER_TESTING_cmd_merchant_get_order ("get-order-merchant-1-2a",
    648                                           merchant_url,
    649                                           "create-proposal-1",
    650                                           TALER_MERCHANT_OSC_PAID,
    651                                           false,
    652                                           MHD_HTTP_OK,
    653                                           NULL),
    654     TALER_TESTING_cmd_merchant_get_orders ("get-orders-1-paid",
    655                                            merchant_url,
    656                                            MHD_HTTP_OK,
    657                                            "create-proposal-1x",
    658                                            "create-proposal-1",
    659                                            NULL),
    660     TALER_TESTING_cmd_merchant_pay_order ("replay-simple",
    661                                           merchant_url,
    662                                           MHD_HTTP_OK,
    663                                           "create-proposal-1",
    664                                           "withdraw-coin-1",
    665                                           "EUR:5",
    666                                           "EUR:4.99",
    667                                           "session-0"),
    668     TALER_TESTING_cmd_check_bank_empty ("check_bank_empty-1"),
    669     TALER_TESTING_cmd_sleep (
    670       "Wait for wire transfer deadline",
    671       3),
    672     CMD_EXEC_AGGREGATOR ("run-aggregator"),
    673     TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-498c",
    674                                            EXCHANGE_URL,
    675                                            "EUR:4.98",
    676                                            exchange_payto,
    677                                            merchant_payto),
    678     TALER_TESTING_cmd_merchant_post_transfer ("post-transfer-1",
    679                                               &cred.ba,
    680                                               merchant_payto,
    681                                               merchant_url,
    682                                               "EUR:4.98",
    683                                               MHD_HTTP_NO_CONTENT,
    684                                               "deposit-simple",
    685                                               NULL),
    686     TALER_TESTING_cmd_depositcheck ("run taler-merchant-depositcheck-1",
    687                                     config_file),
    688     TALER_TESTING_cmd_run_tme ("run taler-merchant-reconciliation-1",
    689                                config_file),
    690     /* Check for settled webhook after reconciliation */
    691     cmd_webhook ("pending-webhooks-settled-w1"),
    692     TALER_TESTING_cmd_checkserver2 ("check-http-server-for-settled-webhook",
    693                                     "launch-http-server-for-webhooks",
    694                                     1,
    695                                     "/",
    696                                     "POST",
    697                                     "settled",
    698                                     "order-settled"),
    699     TALER_TESTING_cmd_merchant_post_transfer2 ("post-transfer-bad",
    700                                                merchant_url,
    701                                                merchant_payto,
    702                                                "EUR:4.98",
    703                                                NULL,
    704                                                /*non-routable IP address
    705                                                so we are sure to not get
    706                                                any reply*/
    707                                                "http://192.0.2.1/404/",
    708                                                MHD_HTTP_NO_CONTENT),
    709     TALER_TESTING_cmd_merchant_get_transfers ("get-transfers-1",
    710                                               merchant_url,
    711                                               merchant_payto,
    712                                               MHD_HTTP_OK,
    713                                               "post-transfer-1",
    714                                               "post-transfer-bad",
    715                                               NULL),
    716     TALER_TESTING_cmd_merchant_delete_transfer ("delete-transfer-1",
    717                                                 merchant_url,
    718                                                 "post-transfer-bad",
    719                                                 MHD_HTTP_NO_CONTENT),
    720     TALER_TESTING_cmd_merchant_get_order2 ("get-order-merchant-1-2b",
    721                                            merchant_url,
    722                                            "create-proposal-1",
    723                                            TALER_MERCHANT_OSC_PAID,
    724                                            true,
    725                                            order_1_transfers, /* "post-transfer-1" */
    726                                            false,
    727                                            NULL,
    728                                            NULL,
    729                                            MHD_HTTP_OK),
    730     TALER_TESTING_cmd_merchant_forget_order ("forget-1",
    731                                              merchant_url,
    732                                              MHD_HTTP_NO_CONTENT,
    733                                              "create-proposal-1",
    734                                              NULL,
    735                                              "$.dummy_obj",
    736                                              NULL),
    737     TALER_TESTING_cmd_merchant_get_order2 ("get-order-merchant-1-forget-1",
    738                                            merchant_url,
    739                                            "create-proposal-1",
    740                                            TALER_MERCHANT_OSC_PAID,
    741                                            true,
    742                                            order_1_transfers,
    743                                            false,
    744                                            NULL,
    745                                            order_1_forgets_1,
    746                                            MHD_HTTP_OK),
    747     TALER_TESTING_cmd_merchant_forget_order ("forget-unforgettable",
    748                                              merchant_url,
    749                                              MHD_HTTP_CONFLICT,
    750                                              "create-proposal-1",
    751                                              NULL,
    752                                              "$.amount",
    753                                              NULL),
    754     TALER_TESTING_cmd_merchant_forget_order ("forget-order-nx",
    755                                              merchant_url,
    756                                              MHD_HTTP_NOT_FOUND,
    757                                              NULL,
    758                                              "nx-order",
    759                                              "$.dummy_obj",
    760                                              NULL),
    761     TALER_TESTING_cmd_merchant_forget_order ("forget-order-array-elem",
    762                                              merchant_url,
    763                                              MHD_HTTP_NO_CONTENT,
    764                                              "create-proposal-1",
    765                                              NULL,
    766                                              "$.dummy_array[0].item",
    767                                              NULL),
    768     TALER_TESTING_cmd_merchant_get_order2 ("get-order-merchant-1-forget-2",
    769                                            merchant_url,
    770                                            "create-proposal-1",
    771                                            TALER_MERCHANT_OSC_PAID,
    772                                            true,
    773                                            order_1_transfers,
    774                                            false,
    775                                            NULL,
    776                                            order_1_forgets_2,
    777                                            MHD_HTTP_OK),
    778     TALER_TESTING_cmd_merchant_forget_order ("forget-order-array-wc",
    779                                              merchant_url,
    780                                              MHD_HTTP_NO_CONTENT,
    781                                              "create-proposal-1",
    782                                              NULL,
    783                                              "$.dummy_array[*].item",
    784                                              NULL),
    785     TALER_TESTING_cmd_merchant_get_order2 ("get-order-merchant-1-forget-3",
    786                                            merchant_url,
    787                                            "create-proposal-1",
    788                                            TALER_MERCHANT_OSC_PAID,
    789                                            true,
    790                                            order_1_transfers,
    791                                            false,
    792                                            NULL,
    793                                            order_1_forgets_3,
    794                                            MHD_HTTP_OK),
    795     TALER_TESTING_cmd_merchant_forget_order ("forget-order-malformed",
    796                                              merchant_url,
    797                                              MHD_HTTP_BAD_REQUEST,
    798                                              "create-proposal-1",
    799                                              NULL,
    800                                              "$.dummy_array[abc].item",
    801                                              NULL),
    802     TALER_TESTING_cmd_merchant_post_products ("post-products-p3",
    803                                               merchant_url,
    804                                               "product-3",
    805                                               "a product",
    806                                               "EUR:1",
    807                                               MHD_HTTP_NO_CONTENT),
    808     TALER_TESTING_cmd_merchant_post_products2 ("post-product-piece",
    809                                                merchant_url,
    810                                                "product-piece",
    811                                                "a product sold by piece",
    812                                                NULL,
    813                                                "Piece",
    814                                                "EUR:1",
    815                                                "",
    816                                                NULL,
    817                                                4,
    818                                                0,
    819                                                NULL,
    820                                                GNUNET_TIME_UNIT_ZERO_TS,
    821                                                MHD_HTTP_NO_CONTENT),
    822     TALER_TESTING_cmd_merchant_post_products_with_unit_prices (
    823       "post-products-dup-currency",
    824       merchant_url,
    825       "product-dup-currency",
    826       "duplicate currency product",
    827       "test-unit",
    828       (const char *[]) { "EUR:1", "EUR:2" },
    829       2,
    830       MHD_HTTP_BAD_REQUEST),
    831     TALER_TESTING_cmd_merchant_post_products2 ("post-products-p4",
    832                                                merchant_url,
    833                                                "product-4age",
    834                                                "an age-restricted product",
    835                                                NULL,
    836                                                "unit",
    837                                                "EUR:1",
    838                                                "", /* image */
    839                                                NULL,
    840                                                4,
    841                                                16 /* minimum age */,
    842                                                NULL,
    843                                                GNUNET_TIME_UNIT_FOREVER_TS,
    844                                                MHD_HTTP_NO_CONTENT),
    845     TALER_TESTING_cmd_merchant_post_products3 ("post-products-frac",
    846                                                merchant_url,
    847                                                "product-frac",
    848                                                "fractional product",
    849                                                json_pack ("{s:s}",
    850                                                           "en",
    851                                                           "fractional product"),
    852                                                "kg",
    853                                                "EUR:1.5",
    854                                                "",
    855                                                json_array (),
    856                                                1,
    857                                                (TALER_MERCHANT_UNIT_FRAC_BASE
    858                                                 * 3)
    859                                                / 4,
    860                                                true,
    861                                                0,
    862                                                NULL,
    863                                                GNUNET_TIME_UNIT_ZERO_TS,
    864                                                MHD_HTTP_NO_CONTENT),
    865     TALER_TESTING_cmd_merchant_get_product ("get-product-frac-post",
    866                                             merchant_url,
    867                                             "product-frac",
    868                                             MHD_HTTP_OK,
    869                                             "post-products-frac"),
    870     TALER_TESTING_cmd_merchant_patch_product_with_unit_prices (
    871       "patch-products-dup-currency",
    872       merchant_url,
    873       "product-3",
    874       "a product",
    875       "can",
    876       (const char *[]) { "EUR:1", "EUR:2" },
    877       2,
    878       MHD_HTTP_BAD_REQUEST),
    879     TALER_TESTING_cmd_merchant_patch_product ("patch-products-p3",
    880                                               merchant_url,
    881                                               "product-3",
    882                                               "a product",
    883                                               json_object (),
    884                                               "can",
    885                                               "EUR:1",
    886                                               "data:image/jpeg;base64,RAWDATA",
    887                                               json_array (),
    888                                               5,
    889                                               0,
    890                                               json_object (),
    891                                               GNUNET_TIME_relative_to_timestamp
    892                                               (
    893                                                 GNUNET_TIME_UNIT_MINUTES),
    894                                               MHD_HTTP_NO_CONTENT),
    895     TALER_TESTING_cmd_merchant_patch_product2 ("patch-product-frac",
    896                                                merchant_url,
    897                                                "product-frac",
    898                                                "fractional product patched",
    899                                                json_pack ("{s:s}",
    900                                                           "en",
    901                                                           "fractional product patched"),
    902                                                "kg",
    903                                                "EUR:1.6",
    904                                                "",
    905                                                json_array (),
    906                                                2,
    907                                                TALER_MERCHANT_UNIT_FRAC_BASE / 4
    908                                                ,
    909                                                true,
    910                                                0,
    911                                                json_object (),
    912                                                GNUNET_TIME_relative_to_timestamp
    913                                                (
    914                                                  GNUNET_TIME_UNIT_MINUTES),
    915                                                MHD_HTTP_NO_CONTENT),
    916     TALER_TESTING_cmd_merchant_get_product ("get-product-frac-patched",
    917                                             merchant_url,
    918                                             "product-frac",
    919                                             MHD_HTTP_OK,
    920                                             "patch-product-frac"),
    921     TALER_TESTING_cmd_merchant_delete_unit ("delete-unit-piece-denied",
    922                                             merchant_url,
    923                                             "Piece",
    924                                             MHD_HTTP_CONFLICT),
    925     TALER_TESTING_cmd_merchant_post_units ("post-unit-piece-conflict",
    926                                            merchant_url,
    927                                            "Piece",
    928                                            "piece",
    929                                            "pc",
    930                                            false,
    931                                            0,
    932                                            true,
    933                                            NULL,
    934                                            NULL,
    935                                            MHD_HTTP_CONFLICT),
    936     /* Per-instance override of a *builtin* unit (#12); only the policy
    937        flags may be changed, hence all name arguments must be NULL. */
    938     TALER_TESTING_cmd_merchant_patch_unit ("patch-unit-builtin",
    939                                            merchant_url,
    940                                            "SizeUnitCm",
    941                                            NULL,
    942                                            NULL,
    943                                            NULL,
    944                                            NULL,
    945                                            false,
    946                                            0,
    947                                            true,
    948                                            MHD_HTTP_NO_CONTENT),
    949     TALER_TESTING_cmd_merchant_get_unit ("get-unit-builtin-patched",
    950                                          merchant_url,
    951                                          "SizeUnitCm",
    952                                          MHD_HTTP_OK,
    953                                          "patch-unit-builtin"),
    954     /* second PATCH must update the existing override row */
    955     TALER_TESTING_cmd_merchant_patch_unit ("patch-unit-builtin-again",
    956                                            merchant_url,
    957                                            "SizeUnitCm",
    958                                            NULL,
    959                                            NULL,
    960                                            NULL,
    961                                            NULL,
    962                                            true,
    963                                            2,
    964                                            true,
    965                                            MHD_HTTP_NO_CONTENT),
    966     TALER_TESTING_cmd_merchant_get_unit ("get-unit-builtin-repatched",
    967                                          merchant_url,
    968                                          "SizeUnitCm",
    969                                          MHD_HTTP_OK,
    970                                          "patch-unit-builtin-again"),
    971     /* renaming a builtin unit remains a conflict */
    972     TALER_TESTING_cmd_merchant_patch_unit ("patch-unit-builtin-rename-denied",
    973                                            merchant_url,
    974                                            "SizeUnitCm",
    975                                            "centimetres",
    976                                            "cm",
    977                                            NULL,
    978                                            NULL,
    979                                            true,
    980                                            2,
    981                                            true,
    982                                            MHD_HTTP_CONFLICT),
    983     TALER_TESTING_cmd_merchant_post_units ("post-unit-bucket",
    984                                            merchant_url,
    985                                            "BucketCustomUnit",
    986                                            "bucket",
    987                                            "bkt",
    988                                            false,
    989                                            0,
    990                                            true,
    991                                            json_pack ("{s:s}", "en", "bucket"),
    992                                            json_pack ("{s:s}", "en", "bkt"),
    993                                            MHD_HTTP_NO_CONTENT),
    994     TALER_TESTING_cmd_merchant_get_unit ("get-unit-bucket",
    995                                          merchant_url,
    996                                          "BucketCustomUnit",
    997                                          MHD_HTTP_OK,
    998                                          "post-unit-bucket"),
    999     TALER_TESTING_cmd_merchant_get_units ("get-units-bucket-list",
   1000                                           merchant_url,
   1001                                           MHD_HTTP_OK,
   1002                                           "post-unit-bucket",
   1003                                           NULL),
   1004     TALER_TESTING_cmd_merchant_patch_unit ("patch-unit-bucket",
   1005                                            merchant_url,
   1006                                            "BucketCustomUnit",
   1007                                            "bucket-updated",
   1008                                            "bkt-upd",
   1009                                            json_pack ("{s:s}", "en",
   1010                                                       "bucket-updated"),
   1011                                            json_pack ("{s:s}", "en", "bkt-upd"),
   1012                                            true,
   1013                                            0,
   1014                                            false,
   1015                                            MHD_HTTP_NO_CONTENT),
   1016     TALER_TESTING_cmd_merchant_get_unit ("get-unit-bucket-patched",
   1017                                          merchant_url,
   1018                                          "BucketCustomUnit",
   1019                                          MHD_HTTP_OK,
   1020                                          "patch-unit-bucket"),
   1021     TALER_TESTING_cmd_merchant_get_units ("get-units-bucket-updated",
   1022                                           merchant_url,
   1023                                           MHD_HTTP_OK,
   1024                                           "patch-unit-bucket",
   1025                                           NULL),
   1026     TALER_TESTING_cmd_merchant_delete_unit ("delete-unit-bucket",
   1027                                             merchant_url,
   1028                                             "BucketCustomUnit",
   1029                                             MHD_HTTP_NO_CONTENT),
   1030     TALER_TESTING_cmd_merchant_get_unit ("get-unit-bucket-deleted",
   1031                                          merchant_url,
   1032                                          "BucketCustomUnit",
   1033                                          MHD_HTTP_NOT_FOUND,
   1034                                          NULL),
   1035     TALER_TESTING_cmd_merchant_post_units ("post-unit-unicorn",
   1036                                            merchant_url,
   1037                                            "UnitUnicorn",
   1038                                            "unicorn",
   1039                                            "uni",
   1040                                            true,
   1041                                            1,
   1042                                            true,
   1043                                            json_pack ("{s:s}", "en", "unicorn"),
   1044                                            json_pack ("{s:s}", "en", "uni"),
   1045                                            MHD_HTTP_NO_CONTENT),
   1046     TALER_TESTING_cmd_merchant_post_products2 ("post-product-unicorn",
   1047                                                merchant_url,
   1048                                                "product-unicorn",
   1049                                                "a unicorn snack",
   1050                                                json_pack ("{s:s}",
   1051                                                           "en",
   1052                                                           "a unicorn snack"),
   1053                                                "UnitUnicorn",
   1054                                                "EUR:3.5",
   1055                                                "",
   1056                                                json_array (),
   1057                                                7,
   1058                                                0,
   1059                                                json_object (),
   1060                                                GNUNET_TIME_UNIT_ZERO_TS,
   1061                                                MHD_HTTP_NO_CONTENT),
   1062     TALER_TESTING_cmd_merchant_get_product2 ("get-product-unicorn-default",
   1063                                              merchant_url,
   1064                                              "product-unicorn",
   1065                                              MHD_HTTP_OK,
   1066                                              "post-product-unicorn",
   1067                                              &expect_unicorn_defaults),
   1068     TALER_TESTING_cmd_merchant_patch_unit ("patch-unit-unicorn",
   1069                                            merchant_url,
   1070                                            "UnitUnicorn",
   1071                                            NULL,
   1072                                            NULL,
   1073                                            NULL,
   1074                                            NULL,
   1075                                            false,
   1076                                            0,
   1077                                            true,
   1078                                            MHD_HTTP_NO_CONTENT),
   1079     TALER_TESTING_cmd_merchant_get_product2 ("get-product-unicorn-patched",
   1080                                              merchant_url,
   1081                                              "product-unicorn",
   1082                                              MHD_HTTP_OK,
   1083                                              "post-product-unicorn",
   1084                                              &expect_unicorn_patched),
   1085     TALER_TESTING_cmd_merchant_delete_product ("delete-product-unicorn",
   1086                                                merchant_url,
   1087                                                "product-unicorn",
   1088                                                MHD_HTTP_NO_CONTENT),
   1089     TALER_TESTING_cmd_merchant_delete_unit ("delete-unit-unicorn",
   1090                                             merchant_url,
   1091                                             "UnitUnicorn",
   1092                                             MHD_HTTP_NO_CONTENT),
   1093     TALER_TESTING_cmd_merchant_lock_product ("lock-product-p3",
   1094                                              merchant_url,
   1095                                              "product-3",
   1096                                              GNUNET_TIME_UNIT_MINUTES,
   1097                                              2,
   1098                                              MHD_HTTP_NO_CONTENT),
   1099     TALER_TESTING_cmd_merchant_lock_product2 (
   1100       "lock-product-p3-float-denied",
   1101       merchant_url,
   1102       "product-3",
   1103       GNUNET_TIME_UNIT_MINUTES,
   1104       1,
   1105       TALER_MERCHANT_UNIT_FRAC_BASE / 2,
   1106       true,
   1107       MHD_HTTP_BAD_REQUEST),
   1108     TALER_TESTING_cmd_merchant_post_orders2 ("create-proposal-p3-float-denied",
   1109                                              cred.cfg,
   1110                                              merchant_url,
   1111                                              MHD_HTTP_BAD_REQUEST,
   1112                                              "order-p3-float-denied",
   1113                                              GNUNET_TIME_UNIT_ZERO_TS,
   1114                                              GNUNET_TIME_UNIT_FOREVER_TS,
   1115                                              true,
   1116                                              "EUR:5.0",
   1117                                              "x-taler-bank",
   1118                                              "product-3/1.5",
   1119                                              "",
   1120                                              NULL),
   1121     TALER_TESTING_cmd_merchant_patch_product2 (
   1122       "patch-product-3-allow-float",
   1123       merchant_url,
   1124       "product-3",
   1125       "a product allow fractional",
   1126       json_pack ("{s:s}",
   1127                  "en",
   1128                  "a product allow fractional"),
   1129       "can",
   1130       "EUR:1",
   1131       "data:image/jpeg;base64,RAWDATA",
   1132       json_array (),
   1133       5,
   1134       0,
   1135       true,
   1136       0,
   1137       json_object (),
   1138       GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_MINUTES),
   1139       MHD_HTTP_NO_CONTENT),
   1140     cmd_transfer_to_exchange ("create-reserve-p3-float",
   1141                               "EUR:5.01"),
   1142     cmd_exec_wirewatch ("wirewatch-p3-float"),
   1143     TALER_TESTING_cmd_check_bank_admin_transfer (
   1144       "check_bank_transfer-p3-float",
   1145       "EUR:5.01",
   1146       payer_payto,
   1147       exchange_payto,
   1148       "create-reserve-p3-float"),
   1149     TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-p3-float",
   1150                                        "create-reserve-p3-float",
   1151                                        "EUR:5",
   1152                                        0,
   1153                                        MHD_HTTP_OK),
   1154     TALER_TESTING_cmd_merchant_lock_product2 (
   1155       "lock-product-p3-float",
   1156       merchant_url,
   1157       "product-3",
   1158       GNUNET_TIME_UNIT_MINUTES,
   1159       1,
   1160       TALER_MERCHANT_UNIT_FRAC_BASE / 2,
   1161       true,
   1162       MHD_HTTP_NO_CONTENT),
   1163     TALER_TESTING_cmd_merchant_post_orders2 ("create-proposal-p3-float",
   1164                                              cred.cfg,
   1165                                              merchant_url,
   1166                                              MHD_HTTP_OK,
   1167                                              "order-p3-float",
   1168                                              GNUNET_TIME_UNIT_ZERO_TS,
   1169                                              GNUNET_TIME_UNIT_FOREVER_TS,
   1170                                              true,
   1171                                              "EUR:5.0",
   1172                                              "x-taler-bank",
   1173                                              "product-3/1.5",
   1174                                              "",
   1175                                              NULL),
   1176     TALER_TESTING_cmd_merchant_claim_order ("claim-order-p3-float",
   1177                                             merchant_url,
   1178                                             MHD_HTTP_OK,
   1179                                             "create-proposal-p3-float",
   1180                                             NULL),
   1181     TALER_TESTING_cmd_merchant_pay_order ("pay-order-p3-float",
   1182                                           merchant_url,
   1183                                           MHD_HTTP_OK,
   1184                                           "create-proposal-p3-float",
   1185                                           "withdraw-coin-p3-float",
   1186                                           "EUR:5",
   1187                                           "EUR:4.99",
   1188                                           "session-p3-float"),
   1189     TALER_TESTING_cmd_sleep (
   1190       "Wait for wire transfer deadline-p3-float",
   1191       3),
   1192     CMD_EXEC_AGGREGATOR ("run-aggregator-p3-float"),
   1193     TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-p3-float",
   1194                                            EXCHANGE_URL,
   1195                                            "EUR:4.98",
   1196                                            exchange_payto,
   1197                                            merchant_payto),
   1198     TALER_TESTING_cmd_merchant_get_order ("get-order-merchant-p3-float-paid",
   1199                                           merchant_url,
   1200                                           "create-proposal-p3-float",
   1201                                           TALER_MERCHANT_OSC_PAID,
   1202                                           false,
   1203                                           MHD_HTTP_OK,
   1204                                           NULL),
   1205     TALER_TESTING_cmd_merchant_patch_product2 (
   1206       "patch-product-3-restore",
   1207       merchant_url,
   1208       "product-3",
   1209       "a product",
   1210       json_pack ("{s:s}",
   1211                  "en",
   1212                  "a product"),
   1213       "can",
   1214       "EUR:1",
   1215       "data:image/jpeg;base64,RAWDATA",
   1216       json_array (),
   1217       5,
   1218       0,
   1219       false,
   1220       0,
   1221       json_object (),
   1222       GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_MINUTES),
   1223       MHD_HTTP_NO_CONTENT),
   1224     TALER_TESTING_cmd_merchant_post_orders2 ("create-proposal-p3-wm-nx",
   1225                                              cred.cfg,
   1226                                              merchant_url,
   1227                                              MHD_HTTP_NOT_FOUND,
   1228                                              "order-p3",
   1229                                              GNUNET_TIME_UNIT_ZERO_TS,
   1230                                              GNUNET_TIME_UNIT_FOREVER_TS,
   1231                                              true,
   1232                                              "EUR:5.0",
   1233                                              "unsupported-wire-method",
   1234                                              "product-3/2",
   1235                                              "", /* locks */
   1236                                              NULL),
   1237     TALER_TESTING_cmd_merchant_post_orders2 ("create-proposal-p3-pd-nx",
   1238                                              cred.cfg,
   1239                                              merchant_url,
   1240                                              MHD_HTTP_NOT_FOUND,
   1241                                              "order-p3",
   1242                                              GNUNET_TIME_UNIT_ZERO_TS,
   1243                                              GNUNET_TIME_UNIT_FOREVER_TS,
   1244                                              true,
   1245                                              "EUR:5.0",
   1246                                              "x-taler-bank",
   1247                                              "unknown-product/2",
   1248                                              "",
   1249                                              NULL),
   1250     TALER_TESTING_cmd_merchant_post_orders2 (
   1251       "create-proposal-p3-not-enough-stock",
   1252       cred.cfg,
   1253       merchant_url,
   1254       MHD_HTTP_GONE,
   1255       "order-p3",
   1256       GNUNET_TIME_UNIT_ZERO_TS,
   1257       GNUNET_TIME_UNIT_FOREVER_TS,
   1258       true,
   1259       "EUR:5.0",
   1260       "x-taler-bank",
   1261       "product-3/24",
   1262       "",
   1263       NULL),
   1264     TALER_TESTING_cmd_merchant_post_orders2 ("create-proposal-p3",
   1265                                              cred.cfg,
   1266                                              merchant_url,
   1267                                              MHD_HTTP_OK,
   1268                                              "order-p3",
   1269                                              GNUNET_TIME_UNIT_ZERO_TS,
   1270                                              GNUNET_TIME_UNIT_FOREVER_TS,
   1271                                              false,
   1272                                              "EUR:5.0",
   1273                                              "x-taler-bank",
   1274                                              "product-3/3",
   1275                                              "lock-product-p3",
   1276                                              NULL),
   1277     TALER_TESTING_cmd_merchant_post_orders2 ("create-proposal-p4-age",
   1278                                              cred.cfg,
   1279                                              merchant_url,
   1280                                              MHD_HTTP_OK,
   1281                                              "order-p4-age",
   1282                                              GNUNET_TIME_UNIT_ZERO_TS,
   1283                                              GNUNET_TIME_UNIT_FOREVER_TS,
   1284                                              false,
   1285                                              "EUR:5.0",
   1286                                              "x-taler-bank",
   1287                                              "product-4age",
   1288                                              "", /* locks */
   1289                                              NULL),
   1290     TALER_TESTING_cmd_merchant_get_order4 ("get-order-merchant-p4-age",
   1291                                            merchant_url,
   1292                                            "create-proposal-p4-age",
   1293                                            TALER_MERCHANT_OSC_CLAIMED,
   1294                                            16,
   1295                                            MHD_HTTP_OK),
   1296     TALER_TESTING_cmd_merchant_delete_order ("delete-order-paid",
   1297                                              merchant_url,
   1298                                              "1",
   1299                                              MHD_HTTP_CONFLICT),
   1300     TALER_TESTING_cmd_merchant_post_orders ("create-proposal-no-id",
   1301                                             cred.cfg,
   1302                                             merchant_url,
   1303                                             MHD_HTTP_OK,
   1304                                             NULL,
   1305                                             GNUNET_TIME_UNIT_ZERO_TS,
   1306                                             GNUNET_TIME_UNIT_FOREVER_TS,
   1307                                             "EUR:5.0"),
   1308     TALER_TESTING_cmd_merchant_delete_webhook ("post-webhooks-pay-w1",
   1309                                                merchant_url,
   1310                                                "webhook-pay-1",
   1311                                                MHD_HTTP_NO_CONTENT),
   1312     TALER_TESTING_cmd_merchant_delete_webhook ("post-webhooks-settled-w1",
   1313                                                merchant_url,
   1314                                                "webhook-settled-1",
   1315                                                MHD_HTTP_NO_CONTENT),
   1316     TALER_TESTING_cmd_check_bank_empty ("check_bank_empty-2"),
   1317     TALER_TESTING_cmd_end ()
   1318   };
   1319   struct TALER_TESTING_Command double_spending[] = {
   1320     TALER_TESTING_cmd_merchant_post_orders ("create-proposal-2",
   1321                                             cred.cfg,
   1322                                             merchant_url,
   1323                                             MHD_HTTP_OK,
   1324                                             "2",
   1325                                             GNUNET_TIME_UNIT_ZERO_TS,
   1326                                             GNUNET_TIME_UNIT_FOREVER_TS,
   1327                                             "EUR:5.0"),
   1328     TALER_TESTING_cmd_merchant_claim_order ("fetch-proposal-2",
   1329                                             merchant_url,
   1330                                             MHD_HTTP_OK,
   1331                                             "create-proposal-2",
   1332                                             NULL),
   1333     TALER_TESTING_cmd_merchant_pay_order ("deposit-double-2",
   1334                                           merchant_url,
   1335                                           MHD_HTTP_CONFLICT,
   1336                                           "create-proposal-2",
   1337                                           "withdraw-coin-1",
   1338                                           "EUR:5",
   1339                                           "EUR:4.99",
   1340                                           NULL),
   1341     TALER_TESTING_cmd_end ()
   1342   };
   1343 
   1344   const char *order_1r_refunds[] = {
   1345     "refund-increase-1r",
   1346     "refund-increase-1r-2",
   1347     NULL
   1348   };
   1349   struct TALER_TESTING_Command refund[] = {
   1350     cmd_transfer_to_exchange ("create-reserve-1r",
   1351                               "EUR:10.02"),
   1352     /**
   1353      * Make a reserve exist, according to the previous transfer.
   1354      */
   1355     cmd_exec_wirewatch ("wirewatch-1r"),
   1356     TALER_TESTING_cmd_check_bank_admin_transfer ("check_bank_transfer-2r",
   1357                                                  "EUR:10.02",
   1358                                                  payer_payto,
   1359                                                  exchange_payto,
   1360                                                  "create-reserve-1r"),
   1361     TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1r",
   1362                                        "create-reserve-1r",
   1363                                        "EUR:5",
   1364                                        0,
   1365                                        MHD_HTTP_OK),
   1366     TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-2r",
   1367                                        "create-reserve-1r",
   1368                                        "EUR:5",
   1369                                        0,
   1370                                        MHD_HTTP_OK),
   1371     /**
   1372      * Check the reserve is depleted.
   1373      */
   1374     TALER_TESTING_cmd_status ("withdraw-status-1r",
   1375                               "create-reserve-1r",
   1376                               "EUR:0",
   1377                               MHD_HTTP_OK),
   1378     TALER_TESTING_cmd_merchant_post_orders ("create-proposal-1r",
   1379                                             cred.cfg,
   1380                                             merchant_url,
   1381                                             MHD_HTTP_OK,
   1382                                             "1r",
   1383                                             GNUNET_TIME_UNIT_ZERO_TS,
   1384                                             GNUNET_TIME_UNIT_FOREVER_TS,
   1385                                             "EUR:5.0"),
   1386     TALER_TESTING_cmd_wallet_poll_order_start ("poll-order-wallet-refund-1-low",
   1387                                                merchant_url,
   1388                                                "create-proposal-1r",
   1389                                                POLL_ORDER_TIMEOUT,
   1390                                                "EUR:0.01"),
   1391     TALER_TESTING_cmd_wallet_poll_order_start (
   1392       "poll-order-wallet-refund-1-high",
   1393       merchant_url,
   1394       "create-proposal-1r",
   1395       POLL_ORDER_TIMEOUT,
   1396       "EUR:0.2"),
   1397     TALER_TESTING_cmd_merchant_pay_order ("pay-for-refund-1r",
   1398                                           merchant_url,
   1399                                           MHD_HTTP_OK,
   1400                                           "create-proposal-1r",
   1401                                           "withdraw-coin-1r",
   1402                                           "EUR:5",
   1403                                           "EUR:4.99",
   1404                                           NULL),
   1405     TALER_TESTING_cmd_poll_order_start ("poll-payment-refund-1",
   1406                                         merchant_url,
   1407                                         "1r", /* proposal name, not cmd ref! */
   1408                                         POLL_ORDER_TIMEOUT),
   1409     TALER_TESTING_cmd_merchant_order_refund ("refund-increase-1r",
   1410                                              merchant_url,
   1411                                              "refund test",
   1412                                              "1r", /* order ID */
   1413                                              "EUR:0.1",
   1414                                              MHD_HTTP_OK),
   1415     TALER_TESTING_cmd_wallet_poll_order_conclude ("poll-order-1-conclude-low",
   1416                                                   MHD_HTTP_OK,
   1417                                                   "EUR:0.1",
   1418                                                   "poll-order-wallet-refund-1-low"),
   1419     TALER_TESTING_cmd_wallet_get_order ("get-order-wallet-1r",
   1420                                         merchant_url,
   1421                                         "create-proposal-1r",
   1422                                         true,
   1423                                         true,
   1424                                         true,
   1425                                         MHD_HTTP_OK),
   1426     TALER_TESTING_cmd_merchant_order_refund ("refund-increase-1r-2",
   1427                                              merchant_url,
   1428                                              "refund test 2",
   1429                                              "1r", /* order ID */
   1430                                              "EUR:1.0",
   1431                                              MHD_HTTP_OK),
   1432     TALER_TESTING_cmd_wallet_poll_order_conclude ("poll-order-1-conclude-high",
   1433                                                   MHD_HTTP_OK,
   1434                                                   "EUR:1.0",
   1435                                                   "poll-order-wallet-refund-1-high"),
   1436     TALER_TESTING_cmd_wallet_get_order ("get-order-wallet-1r-2",
   1437                                         merchant_url,
   1438                                         "create-proposal-1r",
   1439                                         true,
   1440                                         true,
   1441                                         true,
   1442                                         MHD_HTTP_OK),
   1443     TALER_TESTING_cmd_wallet_order_refund ("obtain-refund-1r",
   1444                                            merchant_url,
   1445                                            "create-proposal-1r",
   1446                                            MHD_HTTP_OK,
   1447                                            "refund-increase-1r",
   1448                                            "refund-increase-1r-2",
   1449                                            NULL),
   1450     TALER_TESTING_cmd_wallet_get_order ("get-order-wallet-1r-3",
   1451                                         merchant_url,
   1452                                         "create-proposal-1r",
   1453                                         true,
   1454                                         true,
   1455                                         false,
   1456                                         MHD_HTTP_OK),
   1457     TALER_TESTING_cmd_merchant_get_order ("get-order-merchant-1r",
   1458                                           merchant_url,
   1459                                           "create-proposal-1r",
   1460                                           TALER_MERCHANT_OSC_PAID,
   1461                                           true,
   1462                                           MHD_HTTP_OK,
   1463                                           "refund-increase-1r",
   1464                                           "refund-increase-1r-2",
   1465                                           NULL),
   1466     TALER_TESTING_cmd_merchant_get_order2 ("get-order-merchant-1r-2",
   1467                                            merchant_url,
   1468                                            "create-proposal-1r",
   1469                                            TALER_MERCHANT_OSC_PAID,
   1470                                            false,
   1471                                            NULL,
   1472                                            true,
   1473                                            order_1r_refunds,
   1474                                            NULL,
   1475                                            MHD_HTTP_OK),
   1476     TALER_TESTING_cmd_poll_order_conclude ("poll-payment-refund-conclude-1",
   1477                                            MHD_HTTP_OK,
   1478                                            "poll-payment-refund-1"),
   1479 
   1480     /* Test /refund on a contract that was never paid.  */
   1481     TALER_TESTING_cmd_merchant_post_orders ("create-proposal-not-to-be-paid",
   1482                                             cred.cfg,
   1483                                             merchant_url,
   1484                                             MHD_HTTP_OK,
   1485                                             "1-unpaid",
   1486                                             GNUNET_TIME_UNIT_ZERO_TS,
   1487                                             GNUNET_TIME_UNIT_FOREVER_TS,
   1488                                             "EUR:5.0"),
   1489     /* Try to increase an unpaid proposal.  */
   1490     TALER_TESTING_cmd_merchant_order_refund ("refund-increase-unpaid-proposal",
   1491                                              merchant_url,
   1492                                              "refund test",
   1493                                              "1-unpaid",
   1494                                              "EUR:0.1",
   1495                                              MHD_HTTP_CONFLICT),
   1496     /* Try to increase a non existent proposal.  */
   1497     TALER_TESTING_cmd_merchant_order_refund (
   1498       "refund-increase-nonexistent-proposal",
   1499       merchant_url,
   1500       "refund test",
   1501       "non-existent-id",
   1502       "EUR:0.1",
   1503       MHD_HTTP_NOT_FOUND),
   1504     /*
   1505        The following block will (1) create a new
   1506        reserve, then (2) a proposal, then (3) pay for
   1507        it, and finally (4) attempt to pick up a refund
   1508        from it without any increasing taking place
   1509        in the first place.
   1510     */
   1511     cmd_transfer_to_exchange ("create-reserve-unincreased-refund",
   1512                               "EUR:5.01"),
   1513     cmd_exec_wirewatch ("wirewatch-unincreased-refund"),
   1514     TALER_TESTING_cmd_check_bank_admin_transfer (
   1515       "check_bank_transfer-unincreased-refund",
   1516       "EUR:5.01",
   1517       payer_payto,
   1518       exchange_payto,
   1519       "create-reserve-unincreased-refund"),
   1520     TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-unincreased-refund",
   1521                                        "create-reserve-unincreased-refund",
   1522                                        "EUR:5",
   1523                                        0,
   1524                                        MHD_HTTP_OK),
   1525     TALER_TESTING_cmd_merchant_post_orders (
   1526       "create-proposal-unincreased-refund",
   1527       cred.cfg,
   1528       merchant_url,
   1529       MHD_HTTP_OK,
   1530       "unincreased-proposal",
   1531       GNUNET_TIME_UNIT_ZERO_TS,
   1532       GNUNET_TIME_UNIT_FOREVER_TS,
   1533       "EUR:5.0"),
   1534     TALER_TESTING_cmd_merchant_pay_order ("pay-unincreased-proposal",
   1535                                           merchant_url,
   1536                                           MHD_HTTP_OK,
   1537                                           "create-proposal-unincreased-refund",
   1538                                           "withdraw-coin-unincreased-refund",
   1539                                           "EUR:5",
   1540                                           "EUR:4.99",
   1541                                           NULL),
   1542     TALER_TESTING_cmd_sleep (
   1543       "Wait for wire transfer deadline",
   1544       3),
   1545     CMD_EXEC_AGGREGATOR ("run-aggregator-unincreased-refund"),
   1546     TALER_TESTING_cmd_check_bank_transfer (
   1547       "check_bank_transfer-paid-unincreased-refund",
   1548       EXCHANGE_URL,
   1549       "EUR:8.97", /* '4.98 from above', plus 4.99 from 'pay-for-refund-1r'
   1550                      and MINUS 0.1 MINUS 0.9 from
   1551                      'refund-increase-1r' and 'refund-increase-1r-2' */
   1552       exchange_payto,
   1553       merchant_payto),
   1554     TALER_TESTING_cmd_end ()
   1555   };
   1556 
   1557   struct TALER_TESTING_Command auth[] = {
   1558     TALER_TESTING_cmd_merchant_post_instances ("instance-create-i1a",
   1559                                                merchant_url,
   1560                                                "i1a",
   1561                                                MHD_HTTP_NO_CONTENT),
   1562     TALER_TESTING_cmd_merchant_post_account (
   1563       "instance-create-i1a-account",
   1564       merchant_url_i1a,
   1565       merchant_payto,
   1566       NULL, NULL,
   1567       MHD_HTTP_OK),
   1568     TALER_TESTING_cmd_merchant_get_product ("get-nx-product-i1a-1",
   1569                                             merchant_url_i1a,
   1570                                             "nx-product",
   1571                                             MHD_HTTP_NOT_FOUND,
   1572                                             NULL),
   1573     TALER_TESTING_cmd_merchant_get_products ("get-i1a-products-empty-1",
   1574                                              merchant_url_i1a,
   1575                                              MHD_HTTP_OK,
   1576                                              NULL),
   1577     TALER_TESTING_cmd_merchant_get_product ("get-nx-product-i1a-2",
   1578                                             merchant_url_i1a,
   1579                                             "nx-product",
   1580                                             MHD_HTTP_NOT_FOUND,
   1581                                             NULL),
   1582     TALER_TESTING_cmd_merchant_get_products ("get-i1a-products-empty-2",
   1583                                              merchant_url_i1a,
   1584                                              MHD_HTTP_OK,
   1585                                              NULL),
   1586     TALER_TESTING_cmd_merchant_post_instance_auth (
   1587       "instance-create-i1a-auth-ok",
   1588       merchant_url,
   1589       "i1a",
   1590       "my-secret",
   1591       MHD_HTTP_NO_CONTENT),
   1592     TALER_TESTING_cmd_merchant_get_product ("get-nx-product-i1a-3",
   1593                                             merchant_url_i1a,
   1594                                             "nx-product",
   1595                                             MHD_HTTP_UNAUTHORIZED,
   1596                                             NULL),
   1597     TALER_TESTING_cmd_merchant_get_products ("get-i1a-products-empty-3",
   1598                                              merchant_url_i1a,
   1599                                              MHD_HTTP_UNAUTHORIZED,
   1600                                              NULL),
   1601     TALER_TESTING_cmd_set_authorization ("set-auth-valid",
   1602                                          "Basic aTFhOm15LXNlY3JldA=="),
   1603     TALER_TESTING_cmd_merchant_post_instance_token (
   1604       "instance-create-i1a-token-ok",
   1605       merchant_url,
   1606       "i1a",
   1607       "write", /* scope */
   1608       GNUNET_TIME_UNIT_DAYS, /* duration */
   1609       GNUNET_YES, /* refreshable */
   1610       MHD_HTTP_OK),
   1611     TALER_TESTING_cmd_set_authorization ("unset-auth-valid",
   1612                                          NULL), // Unset header
   1613     TALER_TESTING_cmd_merchant_set_instance_token (
   1614       "instance-create-i1a-token-set",
   1615       "instance-create-i1a-token-ok"),
   1616     TALER_TESTING_cmd_merchant_get_product ("get-nx-product-i1a-4",
   1617                                             merchant_url_i1a,
   1618                                             "nx-product",
   1619                                             MHD_HTTP_NOT_FOUND,
   1620                                             NULL),
   1621     TALER_TESTING_cmd_merchant_get_products ("get-i1a-products-empty-4",
   1622                                              merchant_url_i1a,
   1623                                              MHD_HTTP_OK,
   1624                                              NULL),
   1625     TALER_TESTING_cmd_merchant_delete_instance_token (
   1626       "instance-create-i1a-token-delete",
   1627       merchant_url,
   1628       "i1a",
   1629       MHD_HTTP_NO_CONTENT),
   1630     TALER_TESTING_cmd_merchant_get_product ("get-nx-product-i1a-5",
   1631                                             merchant_url_i1a,
   1632                                             "nx-product",
   1633                                             MHD_HTTP_UNAUTHORIZED,
   1634                                             NULL),
   1635     TALER_TESTING_cmd_merchant_get_products ("get-i1a-products-empty-5",
   1636                                              merchant_url_i1a,
   1637                                              MHD_HTTP_UNAUTHORIZED,
   1638                                              NULL),
   1639     TALER_TESTING_cmd_merchant_purge_instance ("instance-delete-i1a-fail",
   1640                                                merchant_url_i1a,
   1641                                                NULL,
   1642                                                MHD_HTTP_UNAUTHORIZED),
   1643     TALER_TESTING_cmd_set_authorization ("set-token-auth-valid-again",
   1644                                          "Basic aTFhOm15LXNlY3JldA=="),
   1645     TALER_TESTING_cmd_merchant_post_instance_token (
   1646       "set-auth-valid-again",
   1647       merchant_url,
   1648       "i1a",
   1649       "write", /* scope */
   1650       GNUNET_TIME_UNIT_DAYS, /* duration */
   1651       GNUNET_YES, /* refreshable */
   1652       MHD_HTTP_OK),
   1653     TALER_TESTING_cmd_set_authorization ("unset-auth-valid2",
   1654                                          NULL), // Unset header
   1655     TALER_TESTING_cmd_merchant_set_instance_token (
   1656       "instance-create-i1a-token-set-again",
   1657       "set-auth-valid-again"),
   1658     TALER_TESTING_cmd_merchant_post_instance_auth2 (
   1659       "instance-create-i1a-auth-ok-idempotent",
   1660       merchant_url_i1a,
   1661       NULL,
   1662       RFC_8959_PREFIX "my-other-secret",
   1663       "my-secret",
   1664       MHD_HTTP_NO_CONTENT),
   1665     TALER_TESTING_cmd_merchant_post_instance_auth2 (
   1666       "instance-create-i1a-clear-auth",
   1667       merchant_url_i1a,
   1668       NULL,
   1669       NULL,
   1670       "my-other-secret",
   1671       MHD_HTTP_NO_CONTENT),
   1672     TALER_TESTING_cmd_set_authorization ("set-auth-none",
   1673                                          NULL),
   1674     TALER_TESTING_cmd_merchant_purge_instance ("instance-delete-i1a",
   1675                                                merchant_url_i1a,
   1676                                                NULL,
   1677                                                MHD_HTTP_NO_CONTENT),
   1678     TALER_TESTING_cmd_end ()
   1679   };
   1680 
   1681   struct TALER_TESTING_Command pay_again[] = {
   1682     cmd_transfer_to_exchange ("create-reserve-20",
   1683                               "EUR:20.04"),
   1684     cmd_exec_wirewatch ("wirewatch-20"),
   1685     TALER_TESTING_cmd_check_bank_admin_transfer ("check_bank_transfer-10",
   1686                                                  "EUR:20.04",
   1687                                                  payer_payto,
   1688                                                  exchange_payto,
   1689                                                  "create-reserve-20"),
   1690     TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-10a",
   1691                                        "create-reserve-20",
   1692                                        "EUR:5",
   1693                                        0,
   1694                                        MHD_HTTP_OK),
   1695     TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-10b",
   1696                                        "create-reserve-20",
   1697                                        "EUR:5",
   1698                                        0,
   1699                                        MHD_HTTP_OK),
   1700     TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-10c",
   1701                                        "create-reserve-20",
   1702                                        "EUR:5",
   1703                                        0,
   1704                                        MHD_HTTP_OK),
   1705     TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-10d",
   1706                                        "create-reserve-20",
   1707                                        "EUR:5",
   1708                                        0,
   1709                                        MHD_HTTP_OK),
   1710     TALER_TESTING_cmd_status ("withdraw-status-20",
   1711                               "create-reserve-20",
   1712                               "EUR:0",
   1713                               MHD_HTTP_OK),
   1714     TALER_TESTING_cmd_merchant_post_orders ("create-proposal-10",
   1715                                             cred.cfg,
   1716                                             merchant_url,
   1717                                             MHD_HTTP_OK,
   1718                                             "10",
   1719                                             GNUNET_TIME_UNIT_ZERO_TS,
   1720                                             GNUNET_TIME_UNIT_FOREVER_TS,
   1721                                             "EUR:10.0"),
   1722     TALER_TESTING_cmd_merchant_pay_order ("pay-fail-partial-double-10",
   1723                                           merchant_url,
   1724                                           MHD_HTTP_CONFLICT,
   1725                                           "create-proposal-10",
   1726                                           "withdraw-coin-10a;withdraw-coin-1",
   1727                                           "EUR:5",
   1728                                           "EUR:4.99",
   1729                                           NULL),
   1730     TALER_TESTING_cmd_merchant_pay_order ("pay-again-10",
   1731                                           merchant_url,
   1732                                           MHD_HTTP_OK,
   1733                                           "create-proposal-10",
   1734                                           "withdraw-coin-10a;withdraw-coin-10b",
   1735                                           "EUR:5",
   1736                                           "EUR:4.99",
   1737                                           NULL),
   1738     TALER_TESTING_cmd_merchant_pay_order ("pay-too-much-10",
   1739                                           merchant_url,
   1740                                           MHD_HTTP_CONFLICT,
   1741                                           "create-proposal-10",
   1742                                           "withdraw-coin-10c;withdraw-coin-10d",
   1743                                           "EUR:5",
   1744                                           "EUR:4.99",
   1745                                           NULL),
   1746     TALER_TESTING_cmd_sleep (
   1747       "Wait for wire transfer deadline",
   1748       3),
   1749     CMD_EXEC_AGGREGATOR ("run-aggregator-10"),
   1750     TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-9.97-10",
   1751                                            EXCHANGE_URL,
   1752                                            "EUR:9.97",
   1753                                            exchange_payto,
   1754                                            merchant_payto),
   1755     TALER_TESTING_cmd_check_bank_empty ("check_bank_empty-10"),
   1756     TALER_TESTING_cmd_end ()
   1757   };
   1758 
   1759   struct TALER_TESTING_Command pay_abort[] = {
   1760     cmd_transfer_to_exchange ("create-reserve-11",
   1761                               "EUR:10.02"),
   1762     cmd_exec_wirewatch ("wirewatch-11"),
   1763     TALER_TESTING_cmd_check_bank_admin_transfer ("check_bank_transfer-11",
   1764                                                  "EUR:10.02",
   1765                                                  payer_payto,
   1766                                                  exchange_payto,
   1767                                                  "create-reserve-11"),
   1768     TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-11a",
   1769                                        "create-reserve-11",
   1770                                        "EUR:5",
   1771                                        0,
   1772                                        MHD_HTTP_OK),
   1773     TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-11b",
   1774                                        "create-reserve-11",
   1775                                        "EUR:5",
   1776                                        0,
   1777                                        MHD_HTTP_OK),
   1778     TALER_TESTING_cmd_status ("withdraw-status-11",
   1779                               "create-reserve-11",
   1780                               "EUR:0",
   1781                               MHD_HTTP_OK),
   1782     TALER_TESTING_cmd_merchant_post_orders ("create-proposal-11",
   1783                                             cred.cfg,
   1784                                             merchant_url,
   1785                                             MHD_HTTP_OK,
   1786                                             "11",
   1787                                             GNUNET_TIME_UNIT_ZERO_TS,
   1788                                             GNUNET_TIME_UNIT_FOREVER_TS,
   1789                                             "EUR:10.0"),
   1790     TALER_TESTING_cmd_merchant_pay_order ("pay-fail-partial-double-11-good",
   1791                                           merchant_url,
   1792                                           MHD_HTTP_BAD_REQUEST,
   1793                                           "create-proposal-11",
   1794                                           "withdraw-coin-11a",
   1795                                           "EUR:5",
   1796                                           "EUR:4.99",
   1797                                           NULL),
   1798     TALER_TESTING_cmd_merchant_pay_order ("pay-fail-partial-double-11-bad",
   1799                                           merchant_url,
   1800                                           MHD_HTTP_CONFLICT,
   1801                                           "create-proposal-11",
   1802                                           "withdraw-coin-1",
   1803                                           "EUR:5",
   1804                                           "EUR:4.99",
   1805                                           NULL),
   1806     TALER_TESTING_cmd_merchant_order_abort ("pay-abort-11",
   1807                                             merchant_url,
   1808                                             "pay-fail-partial-double-11-good",
   1809                                             MHD_HTTP_OK),
   1810     TALER_TESTING_cmd_sleep (
   1811       "Wait for wire transfer deadline",
   1812       3),
   1813     CMD_EXEC_AGGREGATOR ("run-aggregator-11"),
   1814     TALER_TESTING_cmd_check_bank_empty ("check_bank_empty-11"),
   1815     TALER_TESTING_cmd_end ()
   1816   };
   1817 
   1818   struct TALER_TESTING_Command templates[] = {
   1819     cmd_transfer_to_exchange ("create-reserve-20x",
   1820                               "EUR:20.04"),
   1821     cmd_exec_wirewatch ("wirewatch-20x"),
   1822     TALER_TESTING_cmd_check_bank_admin_transfer ("check_bank_transfer-20x",
   1823                                                  "EUR:20.04",
   1824                                                  payer_payto,
   1825                                                  exchange_payto,
   1826                                                  "create-reserve-20x"),
   1827     TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-xa",
   1828                                        "create-reserve-20x",
   1829                                        "EUR:5",
   1830                                        0,
   1831                                        MHD_HTTP_OK),
   1832     TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-xb",
   1833                                        "create-reserve-20x",
   1834                                        "EUR:5",
   1835                                        0,
   1836                                        MHD_HTTP_OK),
   1837     TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-xc",
   1838                                        "create-reserve-20x",
   1839                                        "EUR:5",
   1840                                        0,
   1841                                        MHD_HTTP_OK),
   1842     TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-xd",
   1843                                        "create-reserve-20x",
   1844                                        "EUR:5",
   1845                                        0,
   1846                                        MHD_HTTP_OK),
   1847     TALER_TESTING_cmd_status ("withdraw-status-20x",
   1848                               "create-reserve-20x",
   1849                               "EUR:0",
   1850                               MHD_HTTP_OK),
   1851     TALER_TESTING_cmd_merchant_get_templates ("get-templates-empty",
   1852                                               merchant_url,
   1853                                               MHD_HTTP_OK,
   1854                                               NULL),
   1855     TALER_TESTING_cmd_merchant_post_templates ("post-templates-t1",
   1856                                                merchant_url,
   1857                                                "template-1",
   1858                                                "a template",
   1859                                                MHD_HTTP_NO_CONTENT),
   1860     TALER_TESTING_cmd_merchant_post_templates ("post-templates-t1-idem",
   1861                                                merchant_url,
   1862                                                "template-1",
   1863                                                "a template",
   1864                                                MHD_HTTP_NO_CONTENT),
   1865     TALER_TESTING_cmd_merchant_post_templates ("post-templates-t1-non-idem",
   1866                                                merchant_url,
   1867                                                "template-1",
   1868                                                "a different template",
   1869                                                MHD_HTTP_CONFLICT),
   1870     TALER_TESTING_cmd_merchant_get_templates ("get-templates-t1",
   1871                                               merchant_url,
   1872                                               MHD_HTTP_OK,
   1873                                               "post-templates-t1",
   1874                                               NULL),
   1875     TALER_TESTING_cmd_merchant_get_template ("get-template-t1",
   1876                                              merchant_url,
   1877                                              "template-1",
   1878                                              MHD_HTTP_OK,
   1879                                              "post-templates-t1"),
   1880     TALER_TESTING_cmd_merchant_wallet_get_template (
   1881       "wallet-get-template-fixed",
   1882       merchant_url,
   1883       "template-1",
   1884       0,
   1885       NULL,
   1886       NULL,
   1887       false,
   1888       0,
   1889       NULL,
   1890       NULL,
   1891       NULL,
   1892       0,
   1893       0,
   1894       EXCHANGE_URL,
   1895       "x-taler-bank",
   1896       MHD_HTTP_OK),
   1897     TALER_TESTING_cmd_merchant_post_templates2 (
   1898       "post-templates-pay-forever",
   1899       merchant_url,
   1900       "template-pay-forever",
   1901       "template with an invalid infinite pay duration",
   1902       NULL,
   1903       GNUNET_JSON_PACK (
   1904         GNUNET_JSON_pack_uint64 ("minimum_age", 0),
   1905         GNUNET_JSON_pack_time_rel ("pay_duration",
   1906                                    GNUNET_TIME_UNIT_FOREVER_REL)),
   1907       MHD_HTTP_BAD_REQUEST),
   1908     TALER_TESTING_cmd_merchant_post_templates ("post-templates-t2",
   1909                                                merchant_url,
   1910                                                "template-2",
   1911                                                "a template",
   1912                                                MHD_HTTP_NO_CONTENT),
   1913     TALER_TESTING_cmd_merchant_patch_template (
   1914       "patch-templates-t2",
   1915       merchant_url,
   1916       "template-2",
   1917       "another template",
   1918       NULL,
   1919       GNUNET_JSON_PACK (
   1920         GNUNET_JSON_pack_uint64 ("minimum_age", 0),
   1921         GNUNET_JSON_pack_time_rel ("pay_duration",
   1922                                    GNUNET_TIME_UNIT_MINUTES)),
   1923       MHD_HTTP_NO_CONTENT),
   1924     TALER_TESTING_cmd_merchant_get_template ("get-template-t2",
   1925                                              merchant_url,
   1926                                              "template-2",
   1927                                              MHD_HTTP_OK,
   1928                                              "patch-templates-t2"),
   1929     TALER_TESTING_cmd_merchant_patch_template (
   1930       "patch-templates-t2-pay-forever",
   1931       merchant_url,
   1932       "template-2",
   1933       "template with an invalid infinite pay duration",
   1934       NULL,
   1935       GNUNET_JSON_PACK (
   1936         GNUNET_JSON_pack_uint64 ("minimum_age", 0),
   1937         GNUNET_JSON_pack_time_rel ("pay_duration",
   1938                                    GNUNET_TIME_UNIT_FOREVER_REL)),
   1939       MHD_HTTP_BAD_REQUEST),
   1940     TALER_TESTING_cmd_merchant_get_template (
   1941       "get-template-t2-after-pay-forever",
   1942       merchant_url,
   1943       "template-2",
   1944       MHD_HTTP_OK,
   1945       "patch-templates-t2"),
   1946     TALER_TESTING_cmd_merchant_get_template ("get-template-nx",
   1947                                              merchant_url,
   1948                                              "template-nx",
   1949                                              MHD_HTTP_NOT_FOUND,
   1950                                              NULL),
   1951     TALER_TESTING_cmd_merchant_post_otp_devices (
   1952       "post-otp-device",
   1953       merchant_url,
   1954       "otp-dev",
   1955       "my OTP device",
   1956       "FEE4P2J",
   1957       TALER_MCA_WITH_PRICE,
   1958       0,
   1959       MHD_HTTP_NO_CONTENT),
   1960     TALER_TESTING_cmd_merchant_patch_template (
   1961       "patch-templates-t3-nx",
   1962       merchant_url,
   1963       "template-3",
   1964       "updated template",
   1965       "otp-dev",
   1966       GNUNET_JSON_PACK (
   1967         GNUNET_JSON_pack_uint64 ("minimum_age", 0),
   1968         GNUNET_JSON_pack_time_rel ("pay_duration",
   1969                                    GNUNET_TIME_UNIT_MINUTES)),
   1970       MHD_HTTP_NOT_FOUND),
   1971     /* Bind template-2 to an existing OTP device ... */
   1972     TALER_TESTING_cmd_merchant_patch_template (
   1973       "patch-templates-t2-otp",
   1974       merchant_url,
   1975       "template-2",
   1976       "a template with an OTP device",
   1977       "otp-dev",
   1978       GNUNET_JSON_PACK (
   1979         GNUNET_JSON_pack_uint64 ("minimum_age", 0),
   1980         GNUNET_JSON_pack_time_rel ("pay_duration",
   1981                                    GNUNET_TIME_UNIT_MINUTES)),
   1982       MHD_HTTP_NO_CONTENT),
   1983     /* ... a PATCH naming an unknown OTP device must be refused
   1984        with 404 and must NOT clear the existing binding (#5) */
   1985     TALER_TESTING_cmd_merchant_patch_template (
   1986       "patch-templates-t2-otp-nx",
   1987       merchant_url,
   1988       "template-2",
   1989       "a template that must not be stored",
   1990       "otp-dev-nx",
   1991       GNUNET_JSON_PACK (
   1992         GNUNET_JSON_pack_uint64 ("minimum_age", 0),
   1993         GNUNET_JSON_pack_time_rel ("pay_duration",
   1994                                    GNUNET_TIME_UNIT_MINUTES)),
   1995       MHD_HTTP_NOT_FOUND),
   1996     /* ... hence the template must still match the successful PATCH */
   1997     TALER_TESTING_cmd_merchant_get_template ("get-template-t2-otp",
   1998                                              merchant_url,
   1999                                              "template-2",
   2000                                              MHD_HTTP_OK,
   2001                                              "patch-templates-t2-otp"),
   2002     TALER_TESTING_cmd_merchant_post_templates2 (
   2003       "post-templates-t3-amount",
   2004       merchant_url,
   2005       "template-amount",
   2006       "a different template with an amount",
   2007       NULL,
   2008       GNUNET_JSON_PACK (
   2009         GNUNET_JSON_pack_uint64 ("minimum_age", 0),
   2010         GNUNET_JSON_pack_time_rel ("pay_duration",
   2011                                    GNUNET_TIME_UNIT_MINUTES),
   2012         GNUNET_JSON_pack_string ("amount",
   2013                                  "EUR:4")),
   2014       MHD_HTTP_NO_CONTENT),
   2015     TALER_TESTING_cmd_merchant_post_templates2 (
   2016       "post-templates-pay-default-omitted",
   2017       merchant_url,
   2018       "template-pay-default-omitted",
   2019       "template without a pay duration",
   2020       NULL,
   2021       GNUNET_JSON_PACK (
   2022         GNUNET_JSON_pack_uint64 ("minimum_age", 0),
   2023         GNUNET_JSON_pack_string ("summary",
   2024                                  "use the instance pay delay"),
   2025         GNUNET_JSON_pack_string ("amount",
   2026                                  "EUR:1")),
   2027       MHD_HTTP_NO_CONTENT),
   2028     TALER_TESTING_cmd_merchant_post_using_templates_with_expected_pay_duration (
   2029       "using-templates-pay-default-omitted",
   2030       "post-templates-pay-default-omitted",
   2031       NULL,
   2032       merchant_url,
   2033       "pay-default-omitted",
   2034       NULL,
   2035       NULL,
   2036       GNUNET_TIME_UNIT_ZERO_TS,
   2037       GNUNET_TIME_UNIT_FOREVER_TS,
   2038       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
   2039                                      2),
   2040       MHD_HTTP_OK),
   2041     TALER_TESTING_cmd_merchant_post_templates2 (
   2042       "post-templates-pay-default-zero",
   2043       merchant_url,
   2044       "template-pay-default-zero",
   2045       "template with a zero pay duration",
   2046       NULL,
   2047       GNUNET_JSON_PACK (
   2048         GNUNET_JSON_pack_uint64 ("minimum_age", 0),
   2049         GNUNET_JSON_pack_time_rel ("pay_duration",
   2050                                    GNUNET_TIME_UNIT_ZERO),
   2051         GNUNET_JSON_pack_string ("summary",
   2052                                  "use the instance pay delay"),
   2053         GNUNET_JSON_pack_string ("amount",
   2054                                  "EUR:1")),
   2055       MHD_HTTP_NO_CONTENT),
   2056     TALER_TESTING_cmd_merchant_post_using_templates_with_expected_pay_duration (
   2057       "using-templates-pay-default-zero",
   2058       "post-templates-pay-default-zero",
   2059       NULL,
   2060       merchant_url,
   2061       "pay-default-zero",
   2062       NULL,
   2063       NULL,
   2064       GNUNET_TIME_UNIT_ZERO_TS,
   2065       GNUNET_TIME_UNIT_FOREVER_TS,
   2066       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
   2067                                      2),
   2068       MHD_HTTP_OK),
   2069     TALER_TESTING_cmd_merchant_post_using_templates (
   2070       "using-templates-t1",
   2071       "post-templates-t1",
   2072       NULL,
   2073       merchant_url,
   2074       "1",
   2075       "summary-1",
   2076       "EUR:9.98",
   2077       GNUNET_TIME_UNIT_ZERO_TS,
   2078       GNUNET_TIME_UNIT_FOREVER_TS,
   2079       MHD_HTTP_OK),
   2080     TALER_TESTING_cmd_merchant_post_using_templates (
   2081       "using-templates-t1-amount-missing",
   2082       "post-templates-t1",
   2083       NULL,
   2084       merchant_url,
   2085       "2",
   2086       "summary-1",
   2087       NULL,
   2088       GNUNET_TIME_UNIT_ZERO_TS,
   2089       GNUNET_TIME_UNIT_FOREVER_TS,
   2090       MHD_HTTP_CONFLICT),
   2091     TALER_TESTING_cmd_merchant_post_using_templates (
   2092       "using-templates-t1-summary-missing",
   2093       "post-templates-t1",
   2094       NULL,
   2095       merchant_url,
   2096       "3",
   2097       NULL,
   2098       "EUR:10",
   2099       GNUNET_TIME_UNIT_ZERO_TS,
   2100       GNUNET_TIME_UNIT_FOREVER_TS,
   2101       MHD_HTTP_CONFLICT),
   2102     TALER_TESTING_cmd_merchant_post_using_templates (
   2103       "using-templates-t1-amount-conflict",
   2104       "post-templates-t3-amount",
   2105       NULL,
   2106       merchant_url,
   2107       "4",
   2108       "summary-1",
   2109       "EUR:10",
   2110       GNUNET_TIME_UNIT_ZERO_TS,
   2111       GNUNET_TIME_UNIT_FOREVER_TS,
   2112       MHD_HTTP_CONFLICT),
   2113     TALER_TESTING_cmd_merchant_post_using_templates (
   2114       "using-templates-t1-amount-duplicate",
   2115       "post-templates-t3-amount",
   2116       NULL,
   2117       merchant_url,
   2118       "4",
   2119       "summary-1",
   2120       "EUR:4",
   2121       GNUNET_TIME_UNIT_ZERO_TS,
   2122       GNUNET_TIME_UNIT_FOREVER_TS,
   2123       MHD_HTTP_CONFLICT),
   2124     TALER_TESTING_cmd_merchant_pay_order ("pay-100",
   2125                                           merchant_url,
   2126                                           MHD_HTTP_OK,
   2127                                           "using-templates-t1",
   2128                                           "withdraw-coin-xa;withdraw-coin-xb",
   2129                                           "EUR:4.99",
   2130                                           "EUR:4.99",
   2131                                           NULL),
   2132     TALER_TESTING_cmd_merchant_delete_template ("get-templates-empty",
   2133                                                 merchant_url,
   2134                                                 "t1",
   2135                                                 MHD_HTTP_NOT_FOUND),
   2136     TALER_TESTING_cmd_merchant_delete_template ("get-templates-empty",
   2137                                                 merchant_url,
   2138                                                 "template-1",
   2139                                                 MHD_HTTP_NO_CONTENT),
   2140     TALER_TESTING_cmd_merchant_post_using_templates (
   2141       "post-templates-t1-deleted",
   2142       "post-templates-t1",
   2143       NULL,
   2144       merchant_url,
   2145       "0",
   2146       "summary-1",
   2147       "EUR:5",
   2148       GNUNET_TIME_UNIT_ZERO_TS,
   2149       GNUNET_TIME_UNIT_FOREVER_TS,
   2150       MHD_HTTP_NOT_FOUND),
   2151     TALER_TESTING_cmd_merchant_post_otp_devices (
   2152       "post-otp-device",
   2153       merchant_url,
   2154       "otp-dev-2",
   2155       "my OTP device",
   2156       "secret",
   2157       TALER_MCA_WITH_PRICE,
   2158       0,
   2159       MHD_HTTP_NO_CONTENT),
   2160     TALER_TESTING_cmd_merchant_post_templates2 (
   2161       "post-templates-with-pos-key",
   2162       merchant_url,
   2163       "template-key",
   2164       "a different template with POS KEY",
   2165       "otp-dev-2",
   2166       GNUNET_JSON_PACK (
   2167         GNUNET_JSON_pack_uint64 ("minimum_age", 0),
   2168         GNUNET_JSON_pack_time_rel ("pay_duration",
   2169                                    GNUNET_TIME_UNIT_MINUTES)),
   2170       MHD_HTTP_NO_CONTENT),
   2171 
   2172     TALER_TESTING_cmd_merchant_post_using_templates (
   2173       "using-templates-pos-key",
   2174       "post-templates-with-pos-key",
   2175       "post-otp-device",
   2176       merchant_url,
   2177       "1",
   2178       "summary-1-pos",
   2179       "EUR:9.98",
   2180       GNUNET_TIME_UNIT_ZERO_TS,
   2181       GNUNET_TIME_UNIT_FOREVER_TS,
   2182       MHD_HTTP_OK),
   2183     TALER_TESTING_cmd_merchant_pay_order ("pay-with-pos",
   2184                                           merchant_url,
   2185                                           MHD_HTTP_OK,
   2186                                           "using-templates-pos-key",
   2187                                           "withdraw-coin-xc;withdraw-coin-xd",
   2188                                           "EUR:4.99",
   2189                                           "EUR:4.99",
   2190                                           NULL),
   2191 
   2192     /* DD 97: the full challenge-signature flow, once per algorithm.
   2193        The backend generates the device key pair and returns only the
   2194        public half; the template instantiation carries a challenge
   2195        chosen on behalf of an offline verifier; and after payment the
   2196        pay command checks the returned pos_confirmation against that
   2197        public key, exactly as the offline device would. */
   2198     cmd_transfer_to_exchange ("create-reserve-dd97",
   2199                               "EUR:40.08"),
   2200     cmd_exec_wirewatch ("wirewatch-dd97"),
   2201     TALER_TESTING_cmd_check_bank_admin_transfer ("check_bank_transfer-dd97",
   2202                                                  "EUR:40.08",
   2203                                                  payer_payto,
   2204                                                  exchange_payto,
   2205                                                  "create-reserve-dd97"),
   2206     TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-dd97a",
   2207                                        "create-reserve-dd97",
   2208                                        "EUR:5",
   2209                                        0,
   2210                                        MHD_HTTP_OK),
   2211     TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-dd97b",
   2212                                        "create-reserve-dd97",
   2213                                        "EUR:5",
   2214                                        0,
   2215                                        MHD_HTTP_OK),
   2216     TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-dd97c",
   2217                                        "create-reserve-dd97",
   2218                                        "EUR:5",
   2219                                        0,
   2220                                        MHD_HTTP_OK),
   2221     TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-dd97d",
   2222                                        "create-reserve-dd97",
   2223                                        "EUR:5",
   2224                                        0,
   2225                                        MHD_HTTP_OK),
   2226 
   2227     TALER_TESTING_cmd_withdraw_amount (
   2228       "withdraw-coin-dd97e", "create-reserve-dd97", "EUR:5", 0, MHD_HTTP_OK),
   2229     TALER_TESTING_cmd_withdraw_amount (
   2230       "withdraw-coin-dd97f", "create-reserve-dd97", "EUR:5", 0, MHD_HTTP_OK),
   2231     TALER_TESTING_cmd_withdraw_amount (
   2232       "withdraw-coin-dd97g", "create-reserve-dd97", "EUR:5", 0, MHD_HTTP_OK),
   2233     TALER_TESTING_cmd_withdraw_amount (
   2234       "withdraw-coin-dd97h", "create-reserve-dd97", "EUR:5", 0, MHD_HTTP_OK),
   2235 
   2236     /* ECDSA (NIST P-256) */
   2237     TALER_TESTING_cmd_merchant_post_otp_devices (
   2238       "post-otp-device-ecdsa-supplied-key",
   2239       merchant_url,
   2240       "otp-dev-ecdsa-supplied-key",
   2241       "client-supplied key is forbidden",
   2242       "JBSWY3DPEHPK3PXP",
   2243       TALER_MCA_ECDSA_CHALLENGE,
   2244       0,
   2245       MHD_HTTP_BAD_REQUEST),
   2246     TALER_TESTING_cmd_merchant_post_otp_devices (
   2247       "post-otp-device-ecdsa",
   2248       merchant_url,
   2249       "otp-dev-ecdsa",
   2250       "an ECDSA challenge device",
   2251       NULL, /* the backend generates the key pair */
   2252       TALER_MCA_ECDSA_CHALLENGE,
   2253       0,
   2254       MHD_HTTP_OK),
   2255     /* Metadata updates remain valid, but changing the signing algorithm
   2256        must fail without breaking the payment confirmation below. */
   2257     TALER_TESTING_cmd_merchant_patch_otp_device (
   2258       "patch-otp-device-ecdsa-same-algorithm",
   2259       merchant_url,
   2260       "otp-dev-ecdsa",
   2261       "an ECDSA challenge device",
   2262       NULL,
   2263       TALER_MCA_ECDSA_CHALLENGE,
   2264       0,
   2265       MHD_HTTP_NO_CONTENT),
   2266     TALER_TESTING_cmd_merchant_patch_otp_device (
   2267       "patch-otp-device-ecdsa-to-eddsa",
   2268       merchant_url,
   2269       "otp-dev-ecdsa",
   2270       "an ECDSA challenge device",
   2271       NULL,
   2272       TALER_MCA_EDDSA_CHALLENGE,
   2273       0,
   2274       MHD_HTTP_CONFLICT),
   2275     TALER_TESTING_cmd_merchant_get_otp_device (
   2276       "get-otp-device-ecdsa-after-rejected-switch",
   2277       merchant_url,
   2278       "otp-dev-ecdsa",
   2279       MHD_HTTP_OK,
   2280       "post-otp-device-ecdsa"),
   2281     TALER_TESTING_cmd_merchant_post_templates2 (
   2282       "post-templates-ecdsa",
   2283       merchant_url,
   2284       "template-ecdsa",
   2285       "template bound to an ECDSA challenge device",
   2286       "otp-dev-ecdsa",
   2287       GNUNET_JSON_PACK (
   2288         GNUNET_JSON_pack_uint64 ("minimum_age", 0),
   2289         GNUNET_JSON_pack_time_rel ("pay_duration",
   2290                                    GNUNET_TIME_UNIT_MINUTES)),
   2291       MHD_HTTP_NO_CONTENT),
   2292     TALER_TESTING_cmd_merchant_post_using_templates2 (
   2293       "using-templates-ecdsa-missing-challenge",
   2294       "post-templates-ecdsa",
   2295       NULL,
   2296       merchant_url,
   2297       "1",
   2298       GNUNET_JSON_PACK (
   2299         GNUNET_JSON_pack_string ("summary", "negative challenge test"),
   2300         GNUNET_JSON_pack_string ("amount", "EUR:9.98")),
   2301       MHD_HTTP_BAD_REQUEST),
   2302     TALER_TESTING_cmd_merchant_post_using_templates2 (
   2303       "using-templates-ecdsa-malformed-challenge",
   2304       "post-templates-ecdsa",
   2305       NULL,
   2306       merchant_url,
   2307       "1",
   2308       GNUNET_JSON_PACK (
   2309         GNUNET_JSON_pack_string ("summary", "negative challenge test"),
   2310         GNUNET_JSON_pack_string ("amount", "EUR:9.98"),
   2311         GNUNET_JSON_pack_string ("challenge", "!")),
   2312       MHD_HTTP_BAD_REQUEST),
   2313     TALER_TESTING_cmd_merchant_post_using_templates2 (
   2314       "using-templates-ecdsa-short-challenge",
   2315       "post-templates-ecdsa",
   2316       NULL,
   2317       merchant_url,
   2318       "1",
   2319       GNUNET_JSON_PACK (
   2320         GNUNET_JSON_pack_string ("summary", "negative challenge test"),
   2321         GNUNET_JSON_pack_string ("amount", "EUR:9.98"),
   2322         GNUNET_JSON_pack_string ("challenge", "00")),
   2323       MHD_HTTP_BAD_REQUEST),
   2324     TALER_TESTING_cmd_merchant_post_using_templates (
   2325       "using-templates-ecdsa",
   2326       "post-templates-ecdsa",
   2327       "post-otp-device-ecdsa",
   2328       merchant_url,
   2329       "1",
   2330       "summary-ecdsa",
   2331       "EUR:9.98",
   2332       GNUNET_TIME_UNIT_ZERO_TS,
   2333       GNUNET_TIME_UNIT_FOREVER_TS,
   2334       MHD_HTTP_OK),
   2335     TALER_TESTING_cmd_merchant_pay_order ("pay-ecdsa-challenge",
   2336                                           merchant_url,
   2337                                           MHD_HTTP_OK,
   2338                                           "using-templates-ecdsa",
   2339                                           "withdraw-coin-dd97a;withdraw-coin-dd97b",
   2340                                           "EUR:4.99",
   2341                                           "EUR:4.99",
   2342                                           NULL),
   2343 
   2344     /* Repeating payment returns a confirmation for the same challenge. */
   2345     TALER_TESTING_cmd_merchant_pay_order (
   2346       "pay-ecdsa-challenge-retry",
   2347       merchant_url,
   2348       MHD_HTTP_OK,
   2349       "using-templates-ecdsa",
   2350       "withdraw-coin-dd97a;withdraw-coin-dd97b",
   2351       "EUR:4.99",
   2352       "EUR:4.99",
   2353       NULL),
   2354 
   2355     /* EdDSA (Ed25519) */
   2356     TALER_TESTING_cmd_merchant_post_otp_devices (
   2357       "post-otp-device-eddsa-supplied-key",
   2358       merchant_url,
   2359       "otp-dev-eddsa-supplied-key",
   2360       "client-supplied key is forbidden",
   2361       "JBSWY3DPEHPK3PXP",
   2362       TALER_MCA_EDDSA_CHALLENGE,
   2363       0,
   2364       MHD_HTTP_BAD_REQUEST),
   2365     TALER_TESTING_cmd_merchant_post_otp_devices (
   2366       "post-otp-device-eddsa",
   2367       merchant_url,
   2368       "otp-dev-eddsa",
   2369       "an EdDSA challenge device",
   2370       NULL, /* the backend generates the key pair */
   2371       TALER_MCA_EDDSA_CHALLENGE,
   2372       0,
   2373       MHD_HTTP_OK),
   2374     /* Metadata updates remain valid, but changing the signing algorithm
   2375        must fail without breaking the payment confirmation below. */
   2376     TALER_TESTING_cmd_merchant_patch_otp_device (
   2377       "patch-otp-device-eddsa-same-algorithm",
   2378       merchant_url,
   2379       "otp-dev-eddsa",
   2380       "an EdDSA challenge device",
   2381       NULL,
   2382       TALER_MCA_EDDSA_CHALLENGE,
   2383       0,
   2384       MHD_HTTP_NO_CONTENT),
   2385     TALER_TESTING_cmd_merchant_patch_otp_device (
   2386       "patch-otp-device-eddsa-to-ecdsa",
   2387       merchant_url,
   2388       "otp-dev-eddsa",
   2389       "an EdDSA challenge device",
   2390       NULL,
   2391       TALER_MCA_ECDSA_CHALLENGE,
   2392       0,
   2393       MHD_HTTP_CONFLICT),
   2394     TALER_TESTING_cmd_merchant_get_otp_device (
   2395       "get-otp-device-eddsa-after-rejected-switch",
   2396       merchant_url,
   2397       "otp-dev-eddsa",
   2398       MHD_HTTP_OK,
   2399       "post-otp-device-eddsa"),
   2400     TALER_TESTING_cmd_merchant_post_templates2 (
   2401       "post-templates-eddsa",
   2402       merchant_url,
   2403       "template-eddsa",
   2404       "template bound to an EdDSA challenge device",
   2405       "otp-dev-eddsa",
   2406       GNUNET_JSON_PACK (
   2407         GNUNET_JSON_pack_uint64 ("minimum_age", 0),
   2408         GNUNET_JSON_pack_time_rel ("pay_duration",
   2409                                    GNUNET_TIME_UNIT_MINUTES)),
   2410       MHD_HTTP_NO_CONTENT),
   2411     TALER_TESTING_cmd_merchant_post_using_templates2 (
   2412       "using-templates-eddsa-missing-challenge",
   2413       "post-templates-eddsa",
   2414       NULL,
   2415       merchant_url,
   2416       "1",
   2417       GNUNET_JSON_PACK (
   2418         GNUNET_JSON_pack_string ("summary", "negative challenge test"),
   2419         GNUNET_JSON_pack_string ("amount", "EUR:9.98")),
   2420       MHD_HTTP_BAD_REQUEST),
   2421     TALER_TESTING_cmd_merchant_post_using_templates2 (
   2422       "using-templates-eddsa-malformed-challenge",
   2423       "post-templates-eddsa",
   2424       NULL,
   2425       merchant_url,
   2426       "1",
   2427       GNUNET_JSON_PACK (
   2428         GNUNET_JSON_pack_string ("summary", "negative challenge test"),
   2429         GNUNET_JSON_pack_string ("amount", "EUR:9.98"),
   2430         GNUNET_JSON_pack_string ("challenge", "!")),
   2431       MHD_HTTP_BAD_REQUEST),
   2432     TALER_TESTING_cmd_merchant_post_using_templates2 (
   2433       "using-templates-eddsa-short-challenge",
   2434       "post-templates-eddsa",
   2435       NULL,
   2436       merchant_url,
   2437       "1",
   2438       GNUNET_JSON_PACK (
   2439         GNUNET_JSON_pack_string ("summary", "negative challenge test"),
   2440         GNUNET_JSON_pack_string ("amount", "EUR:9.98"),
   2441         GNUNET_JSON_pack_string ("challenge", "00")),
   2442       MHD_HTTP_BAD_REQUEST),
   2443     TALER_TESTING_cmd_merchant_post_using_templates (
   2444       "using-templates-eddsa",
   2445       "post-templates-eddsa",
   2446       "post-otp-device-eddsa",
   2447       merchant_url,
   2448       "1",
   2449       "summary-eddsa",
   2450       "EUR:9.98",
   2451       GNUNET_TIME_UNIT_ZERO_TS,
   2452       GNUNET_TIME_UNIT_FOREVER_TS,
   2453       MHD_HTTP_OK),
   2454     TALER_TESTING_cmd_merchant_pay_order ("pay-eddsa-challenge",
   2455                                           merchant_url,
   2456                                           MHD_HTTP_OK,
   2457                                           "using-templates-eddsa",
   2458                                           "withdraw-coin-dd97c;withdraw-coin-dd97d",
   2459                                           "EUR:4.99",
   2460                                           "EUR:4.99",
   2461                                           NULL),
   2462 
   2463     /* Repeating payment returns a confirmation for the same challenge. */
   2464     TALER_TESTING_cmd_merchant_pay_order (
   2465       "pay-eddsa-challenge-retry",
   2466       merchant_url,
   2467       MHD_HTTP_OK,
   2468       "using-templates-eddsa",
   2469       "withdraw-coin-dd97c;withdraw-coin-dd97d",
   2470       "EUR:4.99",
   2471       "EUR:4.99",
   2472       NULL),
   2473 
   2474     TALER_TESTING_cmd_merchant_post_orders_with_otp (
   2475       TALER_TESTING_cmd_merchant_post_orders (
   2476         "direct-ecdsa-challenge", cred.cfg, merchant_url, MHD_HTTP_OK,
   2477         "direct-ecdsa-challenge", GNUNET_TIME_UNIT_ZERO_TS,
   2478         GNUNET_TIME_UNIT_FOREVER_TS, "EUR:9.98"),
   2479       "otp-dev-ecdsa", "post-otp-device-ecdsa", true),
   2480     TALER_TESTING_cmd_merchant_post_orders_with_otp (
   2481       TALER_TESTING_cmd_merchant_post_orders (
   2482         "direct-eddsa-challenge", cred.cfg, merchant_url, MHD_HTTP_OK,
   2483         "direct-eddsa-challenge", GNUNET_TIME_UNIT_ZERO_TS,
   2484         GNUNET_TIME_UNIT_FOREVER_TS, "EUR:9.98"),
   2485       "otp-dev-eddsa", "post-otp-device-eddsa", true),
   2486     TALER_TESTING_cmd_merchant_post_orders_with_otp (
   2487       TALER_TESTING_cmd_merchant_post_orders (
   2488         "direct-missing-challenge", cred.cfg, merchant_url, MHD_HTTP_BAD_REQUEST,
   2489         "direct-missing-challenge", GNUNET_TIME_UNIT_ZERO_TS,
   2490         GNUNET_TIME_UNIT_FOREVER_TS, "EUR:9.98"),
   2491       "otp-dev-ecdsa", NULL, false),
   2492     TALER_TESTING_cmd_merchant_post_orders_with_otp (
   2493       TALER_TESTING_cmd_merchant_post_orders (
   2494         "direct-unexpected-challenge", cred.cfg, merchant_url, MHD_HTTP_BAD_REQUEST,
   2495         "direct-unexpected-challenge", GNUNET_TIME_UNIT_ZERO_TS,
   2496         GNUNET_TIME_UNIT_FOREVER_TS, "EUR:9.98"),
   2497       NULL, NULL, true),
   2498 
   2499     TALER_TESTING_cmd_merchant_pay_order (
   2500       "pay-direct-ecdsa-challenge", merchant_url, MHD_HTTP_OK,
   2501       "direct-ecdsa-challenge", "withdraw-coin-dd97e;withdraw-coin-dd97f",
   2502       "EUR:4.99", "EUR:4.99", NULL),
   2503     TALER_TESTING_cmd_merchant_pay_order (
   2504       "pay-direct-eddsa-challenge", merchant_url, MHD_HTTP_OK,
   2505       "direct-eddsa-challenge", "withdraw-coin-dd97g;withdraw-coin-dd97h",
   2506       "EUR:4.99", "EUR:4.99", NULL),
   2507     TALER_TESTING_cmd_merchant_post_orders_with_otp (
   2508       TALER_TESTING_cmd_merchant_post_orders (
   2509         "direct-totp-unexpected-challenge", cred.cfg, merchant_url, MHD_HTTP_BAD_REQUEST,
   2510         "direct-totp-unexpected-challenge", GNUNET_TIME_UNIT_ZERO_TS,
   2511         GNUNET_TIME_UNIT_FOREVER_TS, "EUR:9.98"),
   2512       "otp-dev-2", NULL, true),
   2513     TALER_TESTING_cmd_merchant_post_templates2 (
   2514       "post-templates-no-challenge-device", merchant_url,
   2515       "template-no-challenge-device", "no device", NULL,
   2516       GNUNET_JSON_PACK (
   2517         GNUNET_JSON_pack_uint64 ("minimum_age", 0),
   2518         GNUNET_JSON_pack_time_rel ("pay_duration", GNUNET_TIME_UNIT_MINUTES)),
   2519       MHD_HTTP_NO_CONTENT),
   2520     TALER_TESTING_cmd_merchant_post_using_templates2 (
   2521       "template-no-device-unexpected-challenge", "post-templates-no-challenge-device", NULL,
   2522       merchant_url, "1",
   2523       GNUNET_JSON_PACK (
   2524         GNUNET_JSON_pack_string ("summary", "unexpected challenge"),
   2525         GNUNET_JSON_pack_string ("amount", "EUR:9.98"),
   2526         GNUNET_JSON_pack_string (
   2527           "challenge", "0000000000000000000000000000000000000000000000000000")),
   2528       MHD_HTTP_BAD_REQUEST),
   2529     TALER_TESTING_cmd_merchant_post_using_templates2 (
   2530       "template-totp-unexpected-challenge", "post-templates-with-pos-key", NULL,
   2531       merchant_url, "1",
   2532       GNUNET_JSON_PACK (
   2533         GNUNET_JSON_pack_string ("summary", "unexpected challenge"),
   2534         GNUNET_JSON_pack_string ("amount", "EUR:9.98"),
   2535         GNUNET_JSON_pack_string (
   2536           "challenge", "0000000000000000000000000000000000000000000000000000")),
   2537       MHD_HTTP_BAD_REQUEST),
   2538 
   2539     /* an algorithm cannot move between the TOTP and the
   2540        challenge-signature families */
   2541     TALER_TESTING_cmd_merchant_post_otp_devices (
   2542       "post-otp-device-mig-totp",
   2543       merchant_url,
   2544       "otp-dev-mig-totp",
   2545       "a TOTP device we try to convert",
   2546       "FEE4P2J",
   2547       TALER_MCA_WITH_PRICE,
   2548       0,
   2549       MHD_HTTP_NO_CONTENT),
   2550     TALER_TESTING_cmd_merchant_patch_otp_device (
   2551       "patch-otp-device-totp-to-ecdsa",
   2552       merchant_url,
   2553       "otp-dev-mig-totp",
   2554       "a TOTP device we try to convert",
   2555       NULL, /* supplying a key here is refused separately */
   2556       TALER_MCA_ECDSA_CHALLENGE,
   2557       0,
   2558       MHD_HTTP_CONFLICT),
   2559     /* the refused PATCH left the device as it was */
   2560     TALER_TESTING_cmd_merchant_get_otp_device (
   2561       "get-otp-device-mig-totp",
   2562       merchant_url,
   2563       "otp-dev-mig-totp",
   2564       MHD_HTTP_OK,
   2565       "post-otp-device-mig-totp"),
   2566     TALER_TESTING_cmd_merchant_post_otp_devices (
   2567       "post-otp-device-mig-eddsa",
   2568       merchant_url,
   2569       "otp-dev-mig-eddsa",
   2570       "an EdDSA device we try to convert",
   2571       NULL, /* the backend generates the key pair */
   2572       TALER_MCA_EDDSA_CHALLENGE,
   2573       0,
   2574       MHD_HTTP_OK),
   2575     TALER_TESTING_cmd_merchant_patch_otp_device (
   2576       "patch-otp-device-eddsa-to-totp",
   2577       merchant_url,
   2578       "otp-dev-mig-eddsa",
   2579       "an EdDSA device we try to convert",
   2580       NULL,
   2581       TALER_MCA_WITH_PRICE,
   2582       0,
   2583       MHD_HTTP_CONFLICT),
   2584     /* the private key was not exposed through the TOTP construction */
   2585     TALER_TESTING_cmd_merchant_get_otp_device (
   2586       "get-otp-device-mig-eddsa",
   2587       merchant_url,
   2588       "otp-dev-mig-eddsa",
   2589       MHD_HTTP_OK,
   2590       "post-otp-device-mig-eddsa"),
   2591     TALER_TESTING_cmd_merchant_patch_otp_device (
   2592       "patch-otp-device-mig-nx",
   2593       merchant_url,
   2594       "otp-dev-mig-nonexistent",
   2595       "a device that was never created",
   2596       NULL,
   2597       TALER_MCA_ECDSA_CHALLENGE,
   2598       0,
   2599       MHD_HTTP_NOT_FOUND),
   2600     /* staying inside the TOTP family is still allowed */
   2601     TALER_TESTING_cmd_merchant_patch_otp_device (
   2602       "patch-otp-device-totp-to-totp",
   2603       merchant_url,
   2604       "otp-dev-mig-totp",
   2605       "a TOTP device we rekeyed",
   2606       "FEE4P2K",
   2607       TALER_MCA_WITHOUT_PRICE,
   2608       0,
   2609       MHD_HTTP_NO_CONTENT),
   2610 
   2611     cmd_transfer_to_exchange ("create-reserve-20y",
   2612                               "EUR:10.02"),
   2613     cmd_exec_wirewatch ("wirewatch-20y"),
   2614     TALER_TESTING_cmd_check_bank_admin_transfer ("check_bank_transfer-20y",
   2615                                                  "EUR:10.02",
   2616                                                  payer_payto,
   2617                                                  exchange_payto,
   2618                                                  "create-reserve-20y"),
   2619     TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-yk",
   2620                                        "create-reserve-20y",
   2621                                        "EUR:5",
   2622                                        0,
   2623                                        MHD_HTTP_OK),
   2624     TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-ykb",
   2625                                        "create-reserve-20y",
   2626                                        "EUR:5",
   2627                                        0,
   2628                                        MHD_HTTP_OK),
   2629     TALER_TESTING_cmd_status ("withdraw-status-20y",
   2630                               "create-reserve-20y",
   2631                               "EUR:0",
   2632                               MHD_HTTP_OK),
   2633     TALER_TESTING_cmd_merchant_post_products_with_unit_prices (
   2634       "post-products-inv-1",
   2635       merchant_url,
   2636       "inv-product-1",
   2637       "Inventory Product One",
   2638       "test-unit",
   2639       (const char *[]) { "EUR:1", "KUDOS:1" },
   2640       2,
   2641       MHD_HTTP_NO_CONTENT),
   2642     TALER_TESTING_cmd_merchant_post_products_with_unit_prices (
   2643       "post-products-inv-2",
   2644       merchant_url,
   2645       "inv-product-2",
   2646       "Inventory Product Two",
   2647       "test-unit",
   2648       (const char *[]) { "EUR:2", "KUDOS:2" },
   2649       2,
   2650       MHD_HTTP_NO_CONTENT),
   2651     TALER_TESTING_cmd_merchant_post_templates2 (
   2652       "post-templates-inv-one",
   2653       merchant_url,
   2654       "template-inv-one",
   2655       "inventory template one",
   2656       NULL,
   2657       GNUNET_JSON_PACK (
   2658         GNUNET_JSON_pack_string ("template_type",
   2659                                  "inventory-cart"),
   2660         GNUNET_JSON_pack_string ("summary",
   2661                                  "inventory template"),
   2662         GNUNET_JSON_pack_time_rel ("pay_duration",
   2663                                    GNUNET_TIME_UNIT_MINUTES),
   2664         GNUNET_JSON_pack_array_steal (
   2665           "selected_products",
   2666           make_selected_products ("inv-product-1",
   2667                                   "inv-product-2")),
   2668         GNUNET_JSON_pack_bool ("choose_one",
   2669                                true)),
   2670       MHD_HTTP_NO_CONTENT),
   2671     TALER_TESTING_cmd_merchant_wallet_get_template (
   2672       "wallet-get-template-inv-one",
   2673       merchant_url,
   2674       "template-inv-one",
   2675       0,
   2676       NULL,
   2677       NULL,
   2678       false,
   2679       0,
   2680       NULL,
   2681       NULL,
   2682       NULL,
   2683       0,
   2684       0,
   2685       EXCHANGE_URL,
   2686       "x-taler-bank",
   2687       MHD_HTTP_OK),
   2688     TALER_TESTING_cmd_merchant_post_using_templates2 (
   2689       "using-templates-inv-one",
   2690       "post-templates-inv-one",
   2691       NULL,
   2692       merchant_url,
   2693       "inv-1",
   2694       GNUNET_JSON_PACK (
   2695         GNUNET_JSON_pack_string ("amount",
   2696                                  "EUR:1"),
   2697         GNUNET_JSON_pack_string ("template_type",
   2698                                  "inventory-cart"),
   2699         GNUNET_JSON_pack_array_steal (
   2700           "inventory_selection",
   2701           make_inventory_selection ("inv-product-1",
   2702                                     "1.0",
   2703                                     NULL,
   2704                                     NULL))),
   2705       MHD_HTTP_OK),
   2706     TALER_TESTING_cmd_merchant_post_templates2 (
   2707       "post-templates-inv-multi",
   2708       merchant_url,
   2709       "template-inv-multi",
   2710       "inventory template multi",
   2711       NULL,
   2712       GNUNET_JSON_PACK (
   2713         GNUNET_JSON_pack_string ("template_type",
   2714                                  "inventory-cart"),
   2715         GNUNET_JSON_pack_string ("summary",
   2716                                  "inventory template multi"),
   2717         GNUNET_JSON_pack_time_rel ("pay_duration",
   2718                                    GNUNET_TIME_UNIT_MINUTES),
   2719         GNUNET_JSON_pack_array_steal (
   2720           "selected_products",
   2721           make_selected_products ("inv-product-1",
   2722                                   "inv-product-2"))),
   2723       MHD_HTTP_NO_CONTENT),
   2724     TALER_TESTING_cmd_merchant_post_using_templates2 (
   2725       "using-templates-inv-multi",
   2726       "post-templates-inv-multi",
   2727       NULL,
   2728       merchant_url,
   2729       "inv-2",
   2730       GNUNET_JSON_PACK (
   2731         GNUNET_JSON_pack_string ("amount",
   2732                                  "EUR:3"),
   2733         GNUNET_JSON_pack_string ("template_type",
   2734                                  "inventory-cart"),
   2735         GNUNET_JSON_pack_array_steal (
   2736           "inventory_selection",
   2737           make_inventory_selection ("inv-product-1",
   2738                                     "1.0",
   2739                                     "inv-product-2",
   2740                                     "1.0"))),
   2741       MHD_HTTP_OK),
   2742     TALER_TESTING_cmd_merchant_post_using_templates2 (
   2743       "using-templates-inv-one-empty",
   2744       "post-templates-inv-one",
   2745       NULL,
   2746       merchant_url,
   2747       "inv-1-empty",
   2748       GNUNET_JSON_PACK (
   2749         GNUNET_JSON_pack_string ("amount",
   2750                                  "EUR:1"),
   2751         GNUNET_JSON_pack_string ("template_type",
   2752                                  "inventory-cart"),
   2753         GNUNET_JSON_pack_array_steal (
   2754           "inventory_selection",
   2755           json_array ())),
   2756       MHD_HTTP_CONFLICT),
   2757     TALER_TESTING_cmd_merchant_post_using_templates2 (
   2758       "using-templates-inv-one-two",
   2759       "post-templates-inv-one",
   2760       NULL,
   2761       merchant_url,
   2762       "inv-1-two",
   2763       GNUNET_JSON_PACK (
   2764         GNUNET_JSON_pack_string ("amount",
   2765                                  "EUR:3"),
   2766         GNUNET_JSON_pack_string ("template_type",
   2767                                  "inventory-cart"),
   2768         GNUNET_JSON_pack_array_steal (
   2769           "inventory_selection",
   2770           make_inventory_selection ("inv-product-1",
   2771                                     "1.0",
   2772                                     "inv-product-2",
   2773                                     "1.0"))),
   2774       MHD_HTTP_CONFLICT),
   2775     TALER_TESTING_cmd_merchant_post_using_templates2 (
   2776       "using-templates-inv-one-tip",
   2777       "post-templates-inv-one",
   2778       NULL,
   2779       merchant_url,
   2780       "inv-1-tip",
   2781       GNUNET_JSON_PACK (
   2782         GNUNET_JSON_pack_string ("amount",
   2783                                  "EUR:1"),
   2784         GNUNET_JSON_pack_string ("tip",
   2785                                  "EUR:1"),
   2786         GNUNET_JSON_pack_string ("template_type",
   2787                                  "inventory-cart"),
   2788         GNUNET_JSON_pack_array_steal (
   2789           "inventory_selection",
   2790           make_inventory_selection ("inv-product-1",
   2791                                     "1.0",
   2792                                     NULL,
   2793                                     NULL))),
   2794       MHD_HTTP_CONFLICT),
   2795     TALER_TESTING_cmd_merchant_post_using_templates2 (
   2796       "using-templates-inv-one-tip-ok",
   2797       "post-templates-inv-one",
   2798       NULL,
   2799       merchant_url,
   2800       "inv-1-tip-ok",
   2801       GNUNET_JSON_PACK (
   2802         GNUNET_JSON_pack_string ("amount",
   2803                                  "EUR:2"),
   2804         GNUNET_JSON_pack_string ("tip",
   2805                                  "EUR:1"),
   2806         GNUNET_JSON_pack_string ("template_type",
   2807                                  "inventory-cart"),
   2808         GNUNET_JSON_pack_array_steal (
   2809           "inventory_selection",
   2810           make_inventory_selection ("inv-product-1",
   2811                                     "1.0",
   2812                                     NULL,
   2813                                     NULL))),
   2814       MHD_HTTP_OK),
   2815     TALER_TESTING_cmd_merchant_post_using_templates2 (
   2816       "using-templates-inv-one-unknown",
   2817       "post-templates-inv-one",
   2818       NULL,
   2819       merchant_url,
   2820       "inv-1-unknown",
   2821       GNUNET_JSON_PACK (
   2822         GNUNET_JSON_pack_string ("amount",
   2823                                  "EUR:1"),
   2824         GNUNET_JSON_pack_string ("template_type",
   2825                                  "inventory-cart"),
   2826         GNUNET_JSON_pack_array_steal (
   2827           "inventory_selection",
   2828           make_inventory_selection ("inv-product-404",
   2829                                     "1.0",
   2830                                     NULL,
   2831                                     NULL))),
   2832       MHD_HTTP_NOT_FOUND),
   2833     TALER_TESTING_cmd_merchant_post_templates2 (
   2834       "post-templates-inv-only",
   2835       merchant_url,
   2836       "template-inv-only",
   2837       "inventory template only",
   2838       NULL,
   2839       GNUNET_JSON_PACK (
   2840         GNUNET_JSON_pack_string ("template_type",
   2841                                  "inventory-cart"),
   2842         GNUNET_JSON_pack_string ("summary",
   2843                                  "inventory template only"),
   2844         GNUNET_JSON_pack_time_rel ("pay_duration",
   2845                                    GNUNET_TIME_UNIT_MINUTES),
   2846         GNUNET_JSON_pack_array_steal (
   2847           "selected_products",
   2848           make_selected_products ("inv-product-1",
   2849                                   NULL))),
   2850       MHD_HTTP_NO_CONTENT),
   2851     TALER_TESTING_cmd_merchant_post_using_templates2 (
   2852       "using-templates-inv-only-wrong",
   2853       "post-templates-inv-only",
   2854       NULL,
   2855       merchant_url,
   2856       "inv-only-wrong",
   2857       GNUNET_JSON_PACK (
   2858         GNUNET_JSON_pack_string ("amount",
   2859                                  "EUR:2"),
   2860         GNUNET_JSON_pack_string ("template_type",
   2861                                  "inventory-cart"),
   2862         GNUNET_JSON_pack_array_steal (
   2863           "inventory_selection",
   2864           make_inventory_selection ("inv-product-2",
   2865                                     "1.0",
   2866                                     NULL,
   2867                                     NULL))),
   2868       MHD_HTTP_CONFLICT),
   2869     TALER_TESTING_cmd_merchant_post_using_templates2 (
   2870       "using-templates-inv-multi-amount-mismatch",
   2871       "post-templates-inv-multi",
   2872       NULL,
   2873       merchant_url,
   2874       "inv-2-mismatch",
   2875       GNUNET_JSON_PACK (
   2876         GNUNET_JSON_pack_string ("amount",
   2877                                  "EUR:4"),
   2878         GNUNET_JSON_pack_string ("template_type",
   2879                                  "inventory-cart"),
   2880         GNUNET_JSON_pack_array_steal (
   2881           "inventory_selection",
   2882           make_inventory_selection ("inv-product-1",
   2883                                     "1.0",
   2884                                     "inv-product-2",
   2885                                     "1.0"))),
   2886       MHD_HTTP_CONFLICT),
   2887     TALER_TESTING_cmd_merchant_post_units ("post-unit-special",
   2888                                            merchant_url,
   2889                                            "special-unit",
   2890                                            "Special Unit",
   2891                                            "sunit",
   2892                                            true,
   2893                                            1,
   2894                                            true,
   2895                                            json_pack ("{s:s}",
   2896                                                       "en",
   2897                                                       "Special Unit"),
   2898                                            json_pack ("{s:s}",
   2899                                                       "en",
   2900                                                       "sunit"),
   2901                                            MHD_HTTP_NO_CONTENT),
   2902     TALER_TESTING_cmd_merchant_post_categories ("post-category-special",
   2903                                                 merchant_url,
   2904                                                 "Category Special",
   2905                                                 json_pack ("{s:s}",
   2906                                                            "en",
   2907                                                            "Category Special"),
   2908                                                 1,
   2909                                                 MHD_HTTP_OK),
   2910     TALER_TESTING_cmd_merchant_post_categories ("post-category-special-2",
   2911                                                 merchant_url,
   2912                                                 "Category Special Two",
   2913                                                 json_pack ("{s:s}",
   2914                                                            "en",
   2915                                                            "Category Special Two"),
   2916                                                 2,
   2917                                                 MHD_HTTP_OK),
   2918     TALER_TESTING_cmd_merchant_post_products_with_categories (
   2919       "post-products-inv-unit-1",
   2920       merchant_url,
   2921       "inv-unit-product-1",
   2922       "Inventory Unit Product One",
   2923       "special-unit",
   2924       "EUR:5",
   2925       1,
   2926       (const uint64_t[]) { 1 },
   2927       true,
   2928       1,
   2929       MHD_HTTP_NO_CONTENT),
   2930     TALER_TESTING_cmd_merchant_post_products2 (
   2931       "post-products-inv-unit-2",
   2932       merchant_url,
   2933       "inv-unit-product-2",
   2934       "Inventory Unit Product Two",
   2935       json_pack ("{s:s}", "en", "Inventory Unit Product Two"),
   2936       "test-unit",
   2937       "EUR:1.2",
   2938       "",
   2939       json_array (),
   2940       -1, /* total stock: infinite */
   2941       0,  /* minimum age */
   2942       json_pack ("{s:s}", "street", "my street"),
   2943       GNUNET_TIME_UNIT_ZERO_TS,
   2944       MHD_HTTP_NO_CONTENT),
   2945     TALER_TESTING_cmd_merchant_post_products_with_categories (
   2946       "post-products-inv-unit-3",
   2947       merchant_url,
   2948       "inv-unit-product-3",
   2949       "Inventory Unit Product Three",
   2950       "test-unit",
   2951       "EUR:9",
   2952       1,
   2953       (const uint64_t[]) { 2 },
   2954       false,
   2955       0,
   2956       MHD_HTTP_NO_CONTENT),
   2957     TALER_TESTING_cmd_merchant_post_templates2 (
   2958       "post-templates-inv-cat-prod-unit",
   2959       merchant_url,
   2960       "template-inv-cat-prod-unit",
   2961       "inventory template category+product unit",
   2962       NULL,
   2963       GNUNET_JSON_PACK (
   2964         GNUNET_JSON_pack_string ("template_type",
   2965                                  "inventory-cart"),
   2966         GNUNET_JSON_pack_string ("summary",
   2967                                  "inventory template category+product unit"),
   2968         GNUNET_JSON_pack_time_rel ("pay_duration",
   2969                                    GNUNET_TIME_UNIT_MINUTES),
   2970         GNUNET_JSON_pack_array_steal (
   2971           "selected_categories",
   2972           make_selected_categories (1,
   2973                                     0)),
   2974         GNUNET_JSON_pack_array_steal (
   2975           "selected_products",
   2976           make_selected_products ("inv-unit-product-2",
   2977                                   "inv-unit-product-3"))),
   2978       MHD_HTTP_NO_CONTENT),
   2979     TALER_TESTING_cmd_merchant_wallet_get_template (
   2980       "wallet-get-template-inv-cat-prod-unit",
   2981       merchant_url,
   2982       "template-inv-cat-prod-unit",
   2983       3,
   2984       "inv-unit-product-1",
   2985       "special-unit",
   2986       true,
   2987       1,
   2988       json_pack ("{s:s}",
   2989                  "en",
   2990                  "sunit"),
   2991       "inv-unit-product-2",
   2992       "inv-unit-product-3",
   2993       1,
   2994       2,
   2995       EXCHANGE_URL,
   2996       "x-taler-bank",
   2997       MHD_HTTP_OK),
   2998     TALER_TESTING_cmd_merchant_post_using_templates2 (
   2999       "using-templates-inv-cat-prod-unit",
   3000       "post-templates-inv-cat-prod-unit",
   3001       NULL,
   3002       merchant_url,
   3003       "inv-cat-prod-unit",
   3004       GNUNET_JSON_PACK (
   3005         GNUNET_JSON_pack_string ("amount",
   3006                                  "EUR:3.2"),
   3007         GNUNET_JSON_pack_string ("template_type",
   3008                                  "inventory-cart"),
   3009         GNUNET_JSON_pack_array_steal (
   3010           "inventory_selection",
   3011           make_inventory_selection ("inv-unit-product-1",
   3012                                     "0.4",
   3013                                     "inv-unit-product-2",
   3014                                     "1"))),
   3015       MHD_HTTP_OK),
   3016     TALER_TESTING_cmd_merchant_pay_order_choices (
   3017       "pay-inv-cat-prod-unit",
   3018       merchant_url,
   3019       MHD_HTTP_OK,
   3020       "using-templates-inv-cat-prod-unit",
   3021       "withdraw-coin-yk",
   3022       "EUR:3.2",
   3023       "EUR:3.2",
   3024       NULL,
   3025       0,
   3026       NULL),
   3027 
   3028 
   3029     TALER_TESTING_cmd_end ()
   3030   };
   3031 
   3032   struct TALER_TESTING_Command webhooks[] = {
   3033     TALER_TESTING_cmd_merchant_get_webhooks ("get-webhooks-empty",
   3034                                              merchant_url,
   3035                                              MHD_HTTP_OK,
   3036                                              NULL),
   3037     TALER_TESTING_cmd_merchant_post_webhooks ("post-webhooks-w1",
   3038                                               merchant_url,
   3039                                               "webhook-1",
   3040                                               "Paid",
   3041                                               MHD_HTTP_NO_CONTENT),
   3042     TALER_TESTING_cmd_merchant_post_webhooks ("post-webhooks-w1-idem",
   3043                                               merchant_url,
   3044                                               "webhook-1",
   3045                                               "Paid",
   3046                                               MHD_HTTP_NO_CONTENT),
   3047     TALER_TESTING_cmd_merchant_post_webhooks ("post-webhooks-w1-non-idem",
   3048                                               merchant_url,
   3049                                               "webhook-1",
   3050                                               "Refund",
   3051                                               MHD_HTTP_CONFLICT),
   3052     TALER_TESTING_cmd_merchant_get_webhooks ("get-webhooks-w1",
   3053                                              merchant_url,
   3054                                              MHD_HTTP_OK,
   3055                                              "post-webhooks-w1",
   3056                                              NULL),
   3057     TALER_TESTING_cmd_merchant_get_webhook ("get-webhook-w1",
   3058                                             merchant_url,
   3059                                             "webhook-1",
   3060                                             MHD_HTTP_OK,
   3061                                             "post-webhooks-w1"),
   3062     TALER_TESTING_cmd_merchant_post_webhooks ("post-webhooks-w2",
   3063                                               merchant_url,
   3064                                               "webhook-2",
   3065                                               "Paid",
   3066                                               MHD_HTTP_NO_CONTENT),
   3067     TALER_TESTING_cmd_merchant_patch_webhook ("patch-webhooks-w2",
   3068                                               merchant_url,
   3069                                               "webhook-2",
   3070                                               "Refund2",
   3071                                               "http://localhost:38188/",
   3072                                               "POST",
   3073                                               "Authorization:WHWOXZXPLL",
   3074                                               "Amount",
   3075                                               MHD_HTTP_NO_CONTENT),
   3076     TALER_TESTING_cmd_merchant_get_webhook ("get-webhook-w2",
   3077                                             merchant_url,
   3078                                             "webhook-2",
   3079                                             MHD_HTTP_OK,
   3080                                             "patch-webhooks-w2"),
   3081     TALER_TESTING_cmd_merchant_get_webhook ("get-webhook-nx",
   3082                                             merchant_url,
   3083                                             "webhook-nx",
   3084                                             MHD_HTTP_NOT_FOUND,
   3085                                             NULL),
   3086     TALER_TESTING_cmd_merchant_patch_webhook ("patch-webhooks-w3-nx",
   3087                                               merchant_url,
   3088                                               "webhook-3",
   3089                                               "Paid2",
   3090                                               "https://example.com",
   3091                                               "POST",
   3092                                               "Authorization:WHWOXZXPLL",
   3093                                               "Amount",
   3094                                               MHD_HTTP_NOT_FOUND),
   3095     TALER_TESTING_cmd_merchant_delete_webhook ("get-webhooks-empty",
   3096                                                merchant_url,
   3097                                                "w1",
   3098                                                MHD_HTTP_NOT_FOUND),
   3099     TALER_TESTING_cmd_merchant_delete_webhook ("get-webhooks-empty",
   3100                                                merchant_url,
   3101                                                "webhook-1",
   3102                                                MHD_HTTP_NO_CONTENT),
   3103     TALER_TESTING_cmd_end ()
   3104   };
   3105   struct TALER_TESTING_Command inventory_webhooks[] = {
   3106     TALER_TESTING_cmd_testserver (
   3107       "launch-http-server-for-inventory-webhooks",
   3108       12346),
   3109     TALER_TESTING_cmd_merchant_post_webhooks2 (
   3110       "post-webhooks-inventory-added",
   3111       merchant_url,
   3112       "webhook-inventory-added",
   3113       "inventory_added",
   3114       "http://localhost:12346/",
   3115       "POST",
   3116       "Taler-test-header: inventory",
   3117       "inventory-added",
   3118       MHD_HTTP_NO_CONTENT),
   3119     TALER_TESTING_cmd_merchant_post_webhooks2 (
   3120       "post-webhooks-inventory-updated",
   3121       merchant_url,
   3122       "webhook-inventory-updated",
   3123       "inventory_updated",
   3124       "http://localhost:12346/",
   3125       "POST",
   3126       "Taler-test-header: inventory",
   3127       "inventory-updated",
   3128       MHD_HTTP_NO_CONTENT),
   3129     TALER_TESTING_cmd_merchant_post_webhooks2 (
   3130       "post-webhooks-inventory-deleted",
   3131       merchant_url,
   3132       "webhook-inventory-deleted",
   3133       "inventory_deleted",
   3134       "http://localhost:12346/",
   3135       "POST",
   3136       "Taler-test-header: inventory",
   3137       "inventory-deleted",
   3138       MHD_HTTP_NO_CONTENT),
   3139     TALER_TESTING_cmd_merchant_post_products (
   3140       "post-product-inventory-hook",
   3141       merchant_url,
   3142       "product-inventory-hook",
   3143       "webhook inventory product",
   3144       "EUR:1",
   3145       MHD_HTTP_NO_CONTENT),
   3146     cmd_webhook ("pending-webhooks-inventory-added"),
   3147     TALER_TESTING_cmd_checkserver2 (
   3148       "check-inventory-webhook-added",
   3149       "launch-http-server-for-inventory-webhooks",
   3150       0,
   3151       "/",
   3152       "POST",
   3153       NULL,
   3154       "inventory-added"),
   3155     TALER_TESTING_cmd_merchant_patch_product (
   3156       "patch-product-inventory-hook",
   3157       merchant_url,
   3158       "product-inventory-hook",
   3159       "webhook inventory product patched",
   3160       json_object (),
   3161       "unit",
   3162       "EUR:2",
   3163       "",
   3164       json_array (),
   3165       5,
   3166       0,
   3167       json_object (),
   3168       GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_MINUTES),
   3169       MHD_HTTP_NO_CONTENT),
   3170     cmd_webhook ("pending-webhooks-inventory-updated"),
   3171     TALER_TESTING_cmd_checkserver2 (
   3172       "check-inventory-webhook-updated",
   3173       "launch-http-server-for-inventory-webhooks",
   3174       1,
   3175       "/",
   3176       "POST",
   3177       NULL,
   3178       "inventory-updated"),
   3179     TALER_TESTING_cmd_merchant_delete_product (
   3180       "delete-product-inventory-hook",
   3181       merchant_url,
   3182       "product-inventory-hook",
   3183       MHD_HTTP_NO_CONTENT),
   3184     cmd_webhook ("pending-webhooks-inventory-deleted"),
   3185     TALER_TESTING_cmd_checkserver2 (
   3186       "check-inventory-webhook-deleted",
   3187       "launch-http-server-for-inventory-webhooks",
   3188       2,
   3189       "/",
   3190       "POST",
   3191       NULL,
   3192       "inventory-deleted"),
   3193     TALER_TESTING_cmd_end ()
   3194   };
   3195   struct TALER_TESTING_Command repurchase[] = {
   3196     cmd_transfer_to_exchange (
   3197       "create-reserve-30x",
   3198       "EUR:30.06"),
   3199     cmd_exec_wirewatch (
   3200       "wirewatch-30x"),
   3201     TALER_TESTING_cmd_check_bank_admin_transfer (
   3202       "check_bank_transfer-30x",
   3203       "EUR:30.06",
   3204       payer_payto,
   3205       exchange_payto,
   3206       "create-reserve-30x"),
   3207     TALER_TESTING_cmd_withdraw_amount (
   3208       "withdraw-coin-rep",
   3209       "create-reserve-30x",
   3210       "EUR:5",
   3211       0,
   3212       MHD_HTTP_OK),
   3213     TALER_TESTING_cmd_merchant_post_orders3 (
   3214       "post-order-repurchase-original",
   3215       cred.cfg,
   3216       merchant_url,
   3217       MHD_HTTP_OK,
   3218       "repurchase-original",
   3219       GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_HOURS),
   3220       GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_MINUTES),
   3221       "https://fulfillment.example.com/",
   3222       "EUR:1.0"),
   3223     TALER_TESTING_cmd_merchant_pay_order (
   3224       "repurchase-pay-first",
   3225       merchant_url,
   3226       MHD_HTTP_OK,
   3227       "post-order-repurchase-original",
   3228       "withdraw-coin-rep",
   3229       "EUR:1.00",
   3230       "EUR:0.99",
   3231       "repurchase-session"),
   3232     TALER_TESTING_cmd_wallet_get_order (
   3233       "repurchase-wallet-check-primary-order",
   3234       merchant_url,
   3235       "post-order-repurchase-original",
   3236       true,
   3237       false,
   3238       false,
   3239       MHD_HTTP_OK),
   3240     TALER_TESTING_cmd_merchant_get_order3 (
   3241       "repurchase-check-primary-payment",
   3242       merchant_url,
   3243       "post-order-repurchase-original",
   3244       TALER_MERCHANT_OSC_PAID,
   3245       "repurchase-session",
   3246       NULL,
   3247       MHD_HTTP_OK),
   3248     TALER_TESTING_cmd_merchant_get_order3 (
   3249       "repurchase-check-primary-payment-bad-binding",
   3250       merchant_url,
   3251       "post-order-repurchase-original",
   3252       TALER_MERCHANT_OSC_CLAIMED, /* someone else has it! */
   3253       "wrong-session",
   3254       NULL,
   3255       MHD_HTTP_OK),
   3256     TALER_TESTING_cmd_merchant_post_orders3 (
   3257       "post-order-repurchase-secondary",
   3258       cred.cfg,
   3259       merchant_url,
   3260       MHD_HTTP_OK,
   3261       "repurchase-secondary",
   3262       GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_HOURS),
   3263       GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_MINUTES),
   3264       "https://fulfillment.example.com/",
   3265       "EUR:1.0"),
   3266     TALER_TESTING_cmd_merchant_get_order3 (
   3267       "repurchase-check-secondary-payment",
   3268       merchant_url,
   3269       "post-order-repurchase-secondary",
   3270       TALER_MERCHANT_OSC_UNPAID,
   3271       "repurchase-session",
   3272       NULL,
   3273       MHD_HTTP_OK),
   3274     TALER_TESTING_cmd_merchant_get_order3 (
   3275       "repurchase-check-secondary-payment",
   3276       merchant_url,
   3277       "post-order-repurchase-secondary",
   3278       TALER_MERCHANT_OSC_UNPAID,
   3279       "repurchase-session",
   3280       "post-order-repurchase-original",
   3281       MHD_HTTP_OK),
   3282     TALER_TESTING_cmd_wallet_get_order2 (
   3283       "repurchase-wallet-check-order-secondary",
   3284       merchant_url,
   3285       "post-order-repurchase-secondary",
   3286       "repurchase-session",
   3287       false,
   3288       false,
   3289       false,
   3290       "post-order-repurchase-original",
   3291       MHD_HTTP_PAYMENT_REQUIRED),
   3292     TALER_TESTING_cmd_wallet_get_order2 (
   3293       "repurchase-wallet-check-order-secondary-bad-session",
   3294       merchant_url,
   3295       "post-order-repurchase-secondary",
   3296       "wrong-session",
   3297       false,
   3298       false,
   3299       false,
   3300       NULL,
   3301       MHD_HTTP_PAYMENT_REQUIRED),
   3302     TALER_TESTING_cmd_merchant_order_refund (
   3303       "refund-repurchased",
   3304       merchant_url,
   3305       "refund repurchase",
   3306       "repurchase-original",
   3307       "EUR:1.0",
   3308       MHD_HTTP_OK),
   3309     TALER_TESTING_cmd_wallet_get_order2 (
   3310       "repurchase-wallet-check-primary-order-refunded-no-session",
   3311       merchant_url,
   3312       "post-order-repurchase-original",
   3313       NULL,
   3314       true,
   3315       true,
   3316       true,
   3317       "post-order-repurchase-original",
   3318       MHD_HTTP_OK),
   3319     TALER_TESTING_cmd_wallet_get_order2 (
   3320       "repurchase-wallet-check-primary-order-refunded",
   3321       merchant_url,
   3322       "post-order-repurchase-original",
   3323       "repurchase-session",
   3324       true,
   3325       true,
   3326       true,
   3327       "post-order-repurchase-original",
   3328       MHD_HTTP_OK),
   3329     TALER_TESTING_cmd_merchant_get_order3 (
   3330       "repurchase-check-refunded",
   3331       merchant_url,
   3332       "post-order-repurchase-secondary",
   3333       TALER_MERCHANT_OSC_CLAIMED,
   3334       "repurchase-session",
   3335       NULL,
   3336       MHD_HTTP_OK),
   3337 
   3338     TALER_TESTING_cmd_end ()
   3339   };
   3340 
   3341   struct TALER_TESTING_Command tokens[] = {
   3342     /**
   3343      * Move money to the exchange's bank account.
   3344      */
   3345     cmd_transfer_to_exchange ("create-reserve-tokens",
   3346                               "EUR:20.03"),
   3347     /**
   3348      * Make a reserve exist, according to the previous transfer.
   3349      */
   3350     cmd_exec_wirewatch ("wirewatch-1"),
   3351     TALER_TESTING_cmd_check_bank_admin_transfer ("check_bank_transfer-tokens",
   3352                                                  "EUR:20.03",
   3353                                                  payer_payto,
   3354                                                  exchange_payto,
   3355                                                  "create-reserve-tokens"),
   3356     TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1",
   3357                                        "create-reserve-tokens",
   3358                                        "EUR:5",
   3359                                        0,
   3360                                        MHD_HTTP_OK),
   3361     TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-2",
   3362                                        "create-reserve-tokens",
   3363                                        "EUR:5",
   3364                                        0,
   3365                                        MHD_HTTP_OK),
   3366     TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-3",
   3367                                        "create-reserve-tokens",
   3368                                        "EUR:5",
   3369                                        0,
   3370                                        MHD_HTTP_OK),
   3371     TALER_TESTING_cmd_merchant_post_tokenfamilies (
   3372       "create-upcoming-tokenfamily",
   3373       merchant_url,
   3374       MHD_HTTP_NO_CONTENT,
   3375       "subscription-upcoming",
   3376       "Upcoming Subscription",
   3377       "An upcoming subscription that is not valid yet.",
   3378       NULL,
   3379       /* In one day */
   3380       GNUNET_TIME_absolute_to_timestamp (
   3381         GNUNET_TIME_absolute_add (
   3382           GNUNET_TIME_timestamp_get ().abs_time,
   3383           GNUNET_TIME_UNIT_DAYS)),
   3384       /* In a year */
   3385       GNUNET_TIME_absolute_to_timestamp (
   3386         GNUNET_TIME_absolute_add (
   3387           GNUNET_TIME_timestamp_get ().abs_time,
   3388           GNUNET_TIME_UNIT_YEARS)),
   3389       GNUNET_TIME_UNIT_MONTHS,
   3390       GNUNET_TIME_UNIT_MONTHS,
   3391       "subscription"),
   3392     TALER_TESTING_cmd_merchant_post_orders_choices (
   3393       "create-order-with-upcoming-output",
   3394       cred.cfg,
   3395       merchant_url,
   3396       MHD_HTTP_OK,
   3397       "subscription-upcoming",
   3398       "A choice in the contract",
   3399       NULL,
   3400       0,
   3401       1,
   3402       "5-upcoming-output",
   3403       GNUNET_TIME_UNIT_ZERO_TS,
   3404       GNUNET_TIME_UNIT_FOREVER_TS,
   3405       "EUR:5.0"),
   3406     TALER_TESTING_cmd_merchant_post_tokenfamilies (
   3407       "create-tokenfamily",
   3408       merchant_url,
   3409       MHD_HTTP_NO_CONTENT,
   3410       "subscription-1",
   3411       "Subscription",
   3412       "A subscription.",
   3413       NULL,
   3414       GNUNET_TIME_UNIT_ZERO_TS,
   3415       GNUNET_TIME_relative_to_timestamp (
   3416         GNUNET_TIME_UNIT_YEARS),
   3417       GNUNET_TIME_UNIT_MONTHS,
   3418       GNUNET_TIME_UNIT_MONTHS,
   3419       "subscription"),
   3420     TALER_TESTING_cmd_merchant_post_orders_choices (
   3421       "create-order-with-output",
   3422       cred.cfg,
   3423       merchant_url,
   3424       MHD_HTTP_OK,
   3425       "subscription-1",
   3426       "A choice in the contract",
   3427       NULL,
   3428       0,
   3429       1,
   3430       "5-output",
   3431       GNUNET_TIME_UNIT_ZERO_TS,
   3432       GNUNET_TIME_UNIT_FOREVER_TS,
   3433       "EUR:5.0"),
   3434     TALER_TESTING_cmd_merchant_pay_order_choices (
   3435       "pay-order-with-output",
   3436       merchant_url,
   3437       MHD_HTTP_OK,
   3438       "create-order-with-output",
   3439       "withdraw-coin-1",
   3440       "EUR:5",
   3441       "EUR:4.99",
   3442       NULL,
   3443       0,
   3444       NULL),
   3445     TALER_TESTING_cmd_merchant_post_orders_choices (
   3446       "create-order-with-input-and-output",
   3447       cred.cfg,
   3448       merchant_url,
   3449       MHD_HTTP_OK,
   3450       "subscription-1",
   3451       "A choice in the contract",
   3452       NULL,
   3453       1,
   3454       1,
   3455       "5-input-output",
   3456       GNUNET_TIME_UNIT_ZERO_TS,
   3457       GNUNET_TIME_UNIT_FOREVER_TS,
   3458       "EUR:0.0"),
   3459     TALER_TESTING_cmd_merchant_pay_order_choices (
   3460       "pay-order-with-input-and-output",
   3461       merchant_url,
   3462       MHD_HTTP_OK,
   3463       "create-order-with-input-and-output",
   3464       "",
   3465       "EUR:0",
   3466       "EUR:0",
   3467       NULL,
   3468       0,
   3469       "pay-order-with-output"),
   3470     /* Paying a free v1 order a second time, but naming a different
   3471        choice, must not look like that other choice was completed. */
   3472     TALER_TESTING_cmd_merchant_post_orders_v1 (
   3473       "create-v1-double-pay",
   3474       merchant_url,
   3475       MHD_HTTP_OK,
   3476       "v1-double-pay",
   3477       GNUNET_TIME_UNIT_ZERO_TS,
   3478       GNUNET_TIME_UNIT_FOREVER_TS,
   3479       "[{\"amount\":\"EUR:0\",\"inputs\":[],\"outputs\":[]},"
   3480       " {\"amount\":\"EUR:0\",\"inputs\":[],\"outputs\":[]}]"),
   3481     TALER_TESTING_cmd_merchant_claim_order ("claim-v1-double-pay",
   3482                                             merchant_url,
   3483                                             MHD_HTTP_OK,
   3484                                             "create-v1-double-pay",
   3485                                             NULL),
   3486     TALER_TESTING_cmd_merchant_pay_order_choices (
   3487       "pay-v1-double-choice0",
   3488       merchant_url,
   3489       MHD_HTTP_OK,
   3490       "claim-v1-double-pay",
   3491       "",
   3492       "EUR:0",
   3493       "EUR:0",
   3494       NULL,
   3495       0,
   3496       NULL),
   3497     TALER_TESTING_cmd_merchant_pay_order_choices (
   3498       "pay-v1-double-choice1",
   3499       merchant_url,
   3500       MHD_HTTP_CONFLICT,
   3501       "claim-v1-double-pay",
   3502       "",
   3503       "EUR:0",
   3504       "EUR:0",
   3505       NULL,
   3506       1,
   3507       NULL),
   3508     // TALER_TESTING_cmd_merchant_pay_order_choices ("idempotent-pay-order-with-input-and-output",
   3509     //                                               merchant_url,
   3510     //                                               MHD_HTTP_OK,
   3511     //                                               "create-order-with-input-and-output",
   3512     //                                               "",
   3513     //                                               "EUR:0",
   3514     //                                               "EUR:0",
   3515     //                                               NULL,
   3516     //                                               0,
   3517     //                                               "pay-order-with-output"),
   3518     TALER_TESTING_cmd_merchant_post_orders_choices (
   3519       "create-another-order-with-input-and-output",
   3520       cred.cfg,
   3521       merchant_url,
   3522       MHD_HTTP_OK,
   3523       "subscription-1",
   3524       "A choice in the contract",
   3525       NULL,
   3526       1,
   3527       1,
   3528       "5-input-output-2",
   3529       GNUNET_TIME_UNIT_ZERO_TS,
   3530       GNUNET_TIME_UNIT_FOREVER_TS,
   3531       "EUR:0.0"),
   3532     TALER_TESTING_cmd_merchant_pay_order_choices ("double-spend-token",
   3533                                                   merchant_url,
   3534                                                   MHD_HTTP_CONFLICT,
   3535                                                   "create-another-order-with-input-and-output",
   3536                                                   "",
   3537                                                   "EUR:0",
   3538                                                   "EUR:0",
   3539                                                   NULL,
   3540                                                   0,
   3541                                                   "pay-order-with-output"),
   3542     /* Token fountains (DD 98) */
   3543     TALER_TESTING_cmd_merchant_post_fountains (
   3544       "create-fountain",
   3545       merchant_url,
   3546       MHD_HTTP_OK,
   3547       "campaign-reference-1",
   3548       GNUNET_TIME_UNIT_HOURS,
   3549       1,
   3550       fountain_grants),
   3551     TALER_TESTING_cmd_merchant_post_fountains (
   3552       "create-fountain-unknown-family",
   3553       merchant_url,
   3554       MHD_HTTP_NOT_FOUND,
   3555       "campaign-with-unknown-family",
   3556       GNUNET_TIME_UNIT_HOURS,
   3557       1,
   3558       &(const struct TALER_MERCHANT_FountainGrant) {
   3559       .token_family_slug = "no-such-token-family",
   3560       .tokens_per_period_limit = 1,
   3561       .tokens_per_period_stash = 1,
   3562       .key_window_size = 0
   3563     }),
   3564     TALER_TESTING_cmd_merchant_post_fountains (
   3565       "create-fountain-other",
   3566       merchant_url,
   3567       MHD_HTTP_OK,
   3568       "campaign-reference-2",
   3569       GNUNET_TIME_UNIT_HOURS,
   3570       1,
   3571       fountain_grants_other),
   3572     /* Withdraw a token from the fountain and unblind+verify it. */
   3573     TALER_TESTING_cmd_merchant_fountain_withdraw (
   3574       "fountain-withdraw-token",
   3575       merchant_url,
   3576       MHD_HTTP_OK,
   3577       "create-fountain",
   3578       "subscription-1",
   3579       GNUNET_TIME_UNIT_ZERO_TS,
   3580       1),
   3581     /* Spend the fountain-issued token in an order: proves that a
   3582        token withdrawn without an order is accepted at payment. */
   3583     TALER_TESTING_cmd_merchant_post_orders_choices (
   3584       "create-order-with-fountain-input",
   3585       cred.cfg,
   3586       merchant_url,
   3587       MHD_HTTP_OK,
   3588       "subscription-1",
   3589       "A choice in the contract",
   3590       NULL,
   3591       1,
   3592       0,
   3593       "5-fountain-input",
   3594       GNUNET_TIME_UNIT_ZERO_TS,
   3595       GNUNET_TIME_UNIT_FOREVER_TS,
   3596       "EUR:0.0"),
   3597     TALER_TESTING_cmd_merchant_pay_order_choices (
   3598       "pay-order-with-fountain-input",
   3599       merchant_url,
   3600       MHD_HTTP_OK,
   3601       "create-order-with-fountain-input",
   3602       "",
   3603       "EUR:0",
   3604       "EUR:0",
   3605       NULL,
   3606       0,
   3607       "fountain-withdraw-token"),
   3608     /* The remaining quota of the period is 2 tokens, so 3 more is
   3609        one too many and must be refused as a whole. */
   3610     TALER_TESTING_cmd_merchant_fountain_withdraw (
   3611       "fountain-withdraw-over-limit",
   3612       merchant_url,
   3613       MHD_HTTP_TOO_MANY_REQUESTS,
   3614       "create-fountain",
   3615       "subscription-1",
   3616       GNUNET_TIME_UNIT_ZERO_TS,
   3617       3),
   3618     /* ... and exactly the remaining 2 must still succeed, proving
   3619        the refused request consumed no quota. */
   3620     TALER_TESTING_cmd_merchant_fountain_withdraw (
   3621       "fountain-withdraw-rest-of-period",
   3622       merchant_url,
   3623       MHD_HTTP_OK,
   3624       "create-fountain",
   3625       "subscription-1",
   3626       GNUNET_TIME_UNIT_ZERO_TS,
   3627       2),
   3628     /* Now the period is exhausted. */
   3629     TALER_TESTING_cmd_merchant_fountain_withdraw (
   3630       "fountain-withdraw-exhausted",
   3631       merchant_url,
   3632       MHD_HTTP_TOO_MANY_REQUESTS,
   3633       "create-fountain",
   3634       "subscription-1",
   3635       GNUNET_TIME_UNIT_ZERO_TS,
   3636       1),
   3637     /* Exercise discount issuance and spending with the same helpers. */
   3638     TALER_TESTING_cmd_merchant_post_tokenfamilies (
   3639       "create-fountain-discount-family",
   3640       merchant_url,
   3641       MHD_HTTP_NO_CONTENT,
   3642       "fountain-discount",
   3643       "Discount",
   3644       "A promotional discount.",
   3645       NULL,
   3646       GNUNET_TIME_UNIT_ZERO_TS,
   3647       GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_YEARS),
   3648       GNUNET_TIME_UNIT_MONTHS,
   3649       GNUNET_TIME_UNIT_MONTHS,
   3650       "discount"),
   3651     TALER_TESTING_cmd_merchant_post_fountains (
   3652       "create-discount-fountain",
   3653       merchant_url,
   3654       MHD_HTTP_OK,
   3655       "discount-campaign",
   3656       GNUNET_TIME_UNIT_HOURS,
   3657       1,
   3658       &(const struct TALER_MERCHANT_FountainGrant) {
   3659       .token_family_slug = "fountain-discount",
   3660       .tokens_per_period_limit = 1,
   3661       .tokens_per_period_stash = 1,
   3662       .key_window_size = 0
   3663     }),
   3664     TALER_TESTING_cmd_merchant_fountain_withdraw (
   3665       "fountain-withdraw-discount",
   3666       merchant_url,
   3667       MHD_HTTP_OK,
   3668       "create-discount-fountain",
   3669       "fountain-discount",
   3670       GNUNET_TIME_UNIT_ZERO_TS,
   3671       1),
   3672     TALER_TESTING_cmd_merchant_post_orders_choices (
   3673       "create-order-with-fountain-discount",
   3674       cred.cfg,
   3675       merchant_url,
   3676       MHD_HTTP_OK,
   3677       "fountain-discount",
   3678       "Redeem promotional discount",
   3679       NULL,
   3680       1,
   3681       0,
   3682       "5-fountain-discount",
   3683       GNUNET_TIME_UNIT_ZERO_TS,
   3684       GNUNET_TIME_UNIT_FOREVER_TS,
   3685       "EUR:0.0"),
   3686     TALER_TESTING_cmd_merchant_pay_order_choices (
   3687       "pay-order-with-fountain-discount",
   3688       merchant_url,
   3689       MHD_HTTP_OK,
   3690       "create-order-with-fountain-discount",
   3691       "",
   3692       "EUR:0",
   3693       "EUR:0",
   3694       NULL,
   3695       0,
   3696       "fountain-withdraw-discount"),
   3697     /* Withdrawing from a family the fountain does not grant is
   3698        covered by test_merchant_fountains.sh, which can post a
   3699        withdraw request without first resolving an issue key. */
   3700     TALER_TESTING_cmd_end ()
   3701   };
   3702 
   3703   const struct DONAU_BearerToken bearer = {
   3704     .token = NULL
   3705   };
   3706 
   3707   struct TALER_TESTING_Command donau[] = {
   3708     TALER_TESTING_cmd_set_var (
   3709       "donau",
   3710       TALER_TESTING_cmd_get_donau ("get-donau",
   3711                                    cred.cfg,
   3712                                    true /* wait for response */)),
   3713     TALER_TESTING_cmd_charity_post_merchant ("post-charity",
   3714                                              "example",
   3715                                              "https://example.com/",
   3716                                              "EUR:50", // max_per_year
   3717                                              &bearer,
   3718                                              "create-another-order-with-input-and-output",
   3719                                              // reusing the merchant_reference for merchant_pub
   3720                                              MHD_HTTP_CREATED),
   3721     TALER_TESTING_cmd_charity_post_merchant ("post-charity-idempotent",
   3722                                              "example",
   3723                                              "https://example.com/",
   3724                                              "EUR:50", // max_per_year
   3725                                              &bearer,
   3726                                              "create-another-order-with-input-and-output",
   3727                                              // reusing the merchant_reference for merchant_pub
   3728                                              MHD_HTTP_CREATED),
   3729     TALER_TESTING_cmd_merchant_post_donau_instance (
   3730       "post-donau-instance",
   3731       merchant_url,
   3732       "create-another-order-with-input-and-output",
   3733       MHD_HTTP_NO_CONTENT),
   3734     TALER_TESTING_cmd_merchant_post_donau_instance (
   3735       "post-donau-instance-idempotent",
   3736       merchant_url,
   3737       "create-another-order-with-input-and-output",
   3738       MHD_HTTP_NO_CONTENT),
   3739     TALER_TESTING_cmd_merchant_get_donau_instances (
   3740       "get-donau-instances-after-insert",
   3741       merchant_url,
   3742       1,
   3743       MHD_HTTP_OK),
   3744     TALER_TESTING_cmd_exec_donaukeyupdate ("run-merchant-donaukeyupdate",
   3745                                            config_file),
   3746     TALER_TESTING_cmd_merchant_get_donau_instances (
   3747       "get-donau-instance",
   3748       merchant_url,
   3749       1,
   3750       MHD_HTTP_OK),
   3751     TALER_TESTING_cmd_merchant_post_orders_donau (
   3752       "create-donau-order",
   3753       cred.cfg,
   3754       merchant_url,
   3755       MHD_HTTP_OK,
   3756       "donau",
   3757       GNUNET_TIME_UNIT_ZERO_TS,
   3758       GNUNET_TIME_UNIT_FOREVER_TS,
   3759       "EUR:1"),
   3760     TALER_TESTING_cmd_merchant_pay_order_donau (
   3761       "pay-donau-order",
   3762       merchant_url,
   3763       MHD_HTTP_OK,
   3764       "create-donau-order",
   3765       "withdraw-coin-3",
   3766       "EUR:1", /* full amount */
   3767       "EUR:0.99", /* amount without fees */
   3768       "EUR:1", /* donation amount */
   3769       NULL,
   3770       0,
   3771       "post-charity",
   3772       GNUNET_TIME_get_current_year (),
   3773       "7560001010000",
   3774       "1234"
   3775       ),
   3776     TALER_TESTING_cmd_merchant_delete_donau_instance (
   3777       "delete-donau-instance",
   3778       merchant_url,
   3779       1,
   3780       MHD_HTTP_NO_CONTENT),
   3781     TALER_TESTING_cmd_merchant_get_donau_instances (
   3782       "get-donau-instances-after-delete",
   3783       merchant_url,
   3784       0,
   3785       MHD_HTTP_OK),
   3786     TALER_TESTING_cmd_end ()
   3787   };
   3788 
   3789   /* Products with categories.  Runs last, as it adds a category and
   3790      products which would otherwise show up in the category- and
   3791      product-based expectations of the 'templates' batch. */
   3792   struct TALER_TESTING_Command product_categories[] = {
   3793     /* 3rd category: the 'templates' batch already created two. */
   3794     TALER_TESTING_cmd_merchant_post_categories ("post-category-pc",
   3795                                                 merchant_url,
   3796                                                 "Category Products",
   3797                                                 json_pack ("{s:s}",
   3798                                                            "en",
   3799                                                            "Category Products"),
   3800                                                 3,
   3801                                                 MHD_HTTP_OK),
   3802     /* Unknown category must yield 404, not a DB failure (500). */
   3803     TALER_TESTING_cmd_merchant_post_products_with_categories (
   3804       "post-products-pc-cat-nx",
   3805       merchant_url,
   3806       "pc-product-nx",
   3807       "product with unknown category",
   3808       "test-unit",
   3809       "EUR:3",
   3810       1,
   3811       (const uint64_t[]) { 424242 },
   3812       false,
   3813       0,
   3814       MHD_HTTP_NOT_FOUND),
   3815     /* Category serials are positive; 0 is malformed. */
   3816     TALER_TESTING_cmd_merchant_post_products_with_categories (
   3817       "post-products-pc-cat-zero",
   3818       merchant_url,
   3819       "pc-product-zero",
   3820       "product with zero category",
   3821       "test-unit",
   3822       "EUR:3",
   3823       1,
   3824       (const uint64_t[]) { 0 },
   3825       false,
   3826       0,
   3827       MHD_HTTP_BAD_REQUEST),
   3828     TALER_TESTING_cmd_merchant_get_product (
   3829       "get-product-pc-nx",
   3830       merchant_url,
   3831       "pc-product-nx",
   3832       MHD_HTTP_NOT_FOUND,
   3833       NULL),
   3834     TALER_TESTING_cmd_merchant_post_products_with_categories (
   3835       "post-products-pc",
   3836       merchant_url,
   3837       "pc-product",
   3838       "product with category",
   3839       "test-unit",
   3840       "EUR:3",
   3841       1,
   3842       (const uint64_t[]) { 3 },
   3843       false,
   3844       0,
   3845       MHD_HTTP_NO_CONTENT),
   3846     /* Same for PATCH: unknown category must yield 404, not 500.  The
   3847        rejected update must not have been applied either, hence the
   3848        deviating description and the GET checking against the POST. */
   3849     TALER_TESTING_cmd_merchant_patch_product_with_categories (
   3850       "patch-products-pc-cat-nx",
   3851       merchant_url,
   3852       "pc-product",
   3853       "product with unapplied update",
   3854       "test-unit",
   3855       "EUR:3",
   3856       1,
   3857       (const uint64_t[]) { 424242 },
   3858       MHD_HTTP_NOT_FOUND),
   3859     TALER_TESTING_cmd_merchant_get_product (
   3860       "get-product-pc-unchanged",
   3861       merchant_url,
   3862       "pc-product",
   3863       MHD_HTTP_OK,
   3864       "post-products-pc"),
   3865     TALER_TESTING_cmd_merchant_patch_product_with_categories (
   3866       "patch-products-pc-cat-zero",
   3867       merchant_url,
   3868       "pc-product",
   3869       "product with unapplied update",
   3870       "test-unit",
   3871       "EUR:3",
   3872       1,
   3873       (const uint64_t[]) { 0 },
   3874       MHD_HTTP_BAD_REQUEST),
   3875     TALER_TESTING_cmd_merchant_get_product (
   3876       "get-product-pc-unchanged-2",
   3877       merchant_url,
   3878       "pc-product",
   3879       MHD_HTTP_OK,
   3880       "post-products-pc"),
   3881     /* Duplicate categories are de-duplicated, not rejected. */
   3882     TALER_TESTING_cmd_merchant_patch_product_with_categories (
   3883       "patch-products-pc-cat-dup",
   3884       merchant_url,
   3885       "pc-product",
   3886       "product with category",
   3887       "test-unit",
   3888       "EUR:3",
   3889       2,
   3890       (const uint64_t[]) { 3, 3 },
   3891       MHD_HTTP_NO_CONTENT),
   3892     TALER_TESTING_cmd_merchant_patch_product_with_categories (
   3893       "patch-products-pc-cat-ok",
   3894       merchant_url,
   3895       "pc-product",
   3896       "product with category",
   3897       "test-unit",
   3898       "EUR:3",
   3899       1,
   3900       (const uint64_t[]) { 3 },
   3901       MHD_HTTP_NO_CONTENT),
   3902     TALER_TESTING_cmd_merchant_get_product (
   3903       "get-product-pc",
   3904       merchant_url,
   3905       "pc-product",
   3906       MHD_HTTP_OK,
   3907       "patch-products-pc-cat-ok"),
   3908     TALER_TESTING_cmd_end ()
   3909   };
   3910 
   3911   struct TALER_TESTING_Command partial_payments[] = {
   3912     /* "taler" is reserved and must be rejected */
   3913     TALER_TESTING_cmd_merchant_post_orders_external (
   3914       "create-dd96-bad-taler",
   3915       merchant_url,
   3916       MHD_HTTP_BAD_REQUEST,
   3917       "dd96-bad-taler",
   3918       GNUNET_TIME_UNIT_ZERO_TS,
   3919       GNUNET_TIME_UNIT_FOREVER_TS,
   3920       "EUR:2",
   3921       "[{\"method\":\"taler\",\"id\":\"t1\",\"amount\":\"EUR:1\"}]"),
   3922     /* mixed currencies must be rejected */
   3923     TALER_TESTING_cmd_merchant_post_orders_external (
   3924       "create-dd96-bad-currency",
   3925       merchant_url,
   3926       MHD_HTTP_BAD_REQUEST,
   3927       "dd96-bad-currency",
   3928       GNUNET_TIME_UNIT_ZERO_TS,
   3929       GNUNET_TIME_UNIT_FOREVER_TS,
   3930       "EUR:2",
   3931       "[{\"method\":\"cash\",\"id\":\"c1\",\"amount\":\"USD:1\"}]"),
   3932     /* nested method-specific fields must be rejected */
   3933     TALER_TESTING_cmd_merchant_post_orders_external (
   3934       "create-dd96-bad-nested",
   3935       merchant_url,
   3936       MHD_HTTP_BAD_REQUEST,
   3937       "dd96-bad-nested",
   3938       GNUNET_TIME_UNIT_ZERO_TS,
   3939       GNUNET_TIME_UNIT_FOREVER_TS,
   3940       "EUR:2",
   3941       "[{\"method\":\"cash\",\"id\":\"c1\",\"amount\":\"EUR:1\","
   3942       "\"details\":{\"register\":1}}]"),
   3943     /* valid mixed order with flat method-specific fields */
   3944     TALER_TESTING_cmd_merchant_post_orders_external (
   3945       "create-dd96-mixed",
   3946       merchant_url,
   3947       MHD_HTTP_OK,
   3948       "dd96-mixed",
   3949       GNUNET_TIME_UNIT_ZERO_TS,
   3950       GNUNET_TIME_UNIT_FOREVER_TS,
   3951       "EUR:2",
   3952       "[{\"method\":\"cash\",\"id\":\"cash1\",\"amount\":\"EUR:3\","
   3953       "\"cashier_number\":\"7\"}]"),
   3954     /* normal deletion of orders with external payments is refused */
   3955     TALER_TESTING_cmd_merchant_delete_order2 ("delete-dd96-mixed-noforce",
   3956                                               merchant_url,
   3957                                               "dd96-mixed",
   3958                                               false,
   3959                                               MHD_HTTP_CONFLICT),
   3960     /* ... but forced deletion works */
   3961     TALER_TESTING_cmd_merchant_delete_order2 ("delete-dd96-mixed-force",
   3962                                               merchant_url,
   3963                                               "dd96-mixed",
   3964                                               true,
   3965                                               MHD_HTTP_NO_CONTENT),
   3966     /* collect of unknown orders fails */
   3967     TALER_TESTING_cmd_merchant_collect_order ("collect-dd96-nx",
   3968                                               merchant_url,
   3969                                               "dd96-nx",
   3970                                               NULL,
   3971                                               -1,
   3972                                               MHD_HTTP_NOT_FOUND),
   3973     /* collect of orders with a nonzero Taler amount fails */
   3974     TALER_TESTING_cmd_merchant_post_orders_external (
   3975       "create-dd96-nonzero",
   3976       merchant_url,
   3977       MHD_HTTP_OK,
   3978       "dd96-nonzero",
   3979       GNUNET_TIME_UNIT_ZERO_TS,
   3980       GNUNET_TIME_UNIT_FOREVER_TS,
   3981       "EUR:2",
   3982       "[{\"method\":\"cash\",\"id\":\"cash1\",\"amount\":\"EUR:3\"}]"),
   3983     TALER_TESTING_cmd_merchant_collect_order ("collect-dd96-nonzero",
   3984                                               merchant_url,
   3985                                               "dd96-nonzero",
   3986                                               NULL,
   3987                                               -1,
   3988                                               MHD_HTTP_CONFLICT),
   3989     /* collect of orders claimed by a wallet fails */
   3990     TALER_TESTING_cmd_merchant_post_orders ("create-dd96-claimed",
   3991                                             cred.cfg,
   3992                                             merchant_url,
   3993                                             MHD_HTTP_OK,
   3994                                             "dd96-claimed",
   3995                                             GNUNET_TIME_UNIT_ZERO_TS,
   3996                                             GNUNET_TIME_UNIT_FOREVER_TS,
   3997                                             "EUR:0"),
   3998     TALER_TESTING_cmd_merchant_collect_order ("collect-dd96-claimed",
   3999                                               merchant_url,
   4000                                               "dd96-claimed",
   4001                                               NULL,
   4002                                               -1,
   4003                                               MHD_HTTP_CONFLICT),
   4004     /* collect a zero-Taler order settled fully via cash */
   4005     TALER_TESTING_cmd_merchant_post_orders_external (
   4006       "create-dd96-free",
   4007       merchant_url,
   4008       MHD_HTTP_OK,
   4009       "dd96-free",
   4010       GNUNET_TIME_UNIT_ZERO_TS,
   4011       GNUNET_TIME_UNIT_FOREVER_TS,
   4012       "EUR:0",
   4013       "[{\"method\":\"cash\",\"id\":\"cash1\",\"amount\":\"EUR:3\"}]"),
   4014     TALER_TESTING_cmd_merchant_collect_order ("collect-dd96-free",
   4015                                               merchant_url,
   4016                                               "dd96-free",
   4017                                               "pos-1",
   4018                                               -1,
   4019                                               MHD_HTTP_OK),
   4020     /* collect is idempotent */
   4021     TALER_TESTING_cmd_merchant_collect_order ("collect-dd96-free-again",
   4022                                               merchant_url,
   4023                                               "dd96-free",
   4024                                               "pos-1",
   4025                                               -1,
   4026                                               MHD_HTTP_OK),
   4027     /* v0 orders have no choices, so naming one is a client error;
   4028        use a fresh order as an already collected one replays instead */
   4029     TALER_TESTING_cmd_merchant_post_orders_external (
   4030       "create-dd96-v0-choice",
   4031       merchant_url,
   4032       MHD_HTTP_OK,
   4033       "dd96-v0-choice",
   4034       GNUNET_TIME_UNIT_ZERO_TS,
   4035       GNUNET_TIME_UNIT_FOREVER_TS,
   4036       "EUR:0",
   4037       "[{\"method\":\"cash\",\"id\":\"cash1\",\"amount\":\"EUR:1\"}]"),
   4038     TALER_TESTING_cmd_merchant_collect_order ("collect-dd96-v0-with-choice",
   4039                                               merchant_url,
   4040                                               "dd96-v0-choice",
   4041                                               NULL,
   4042                                               0,
   4043                                               MHD_HTTP_BAD_REQUEST),
   4044     /* a free v1 order with two choices to pick from */
   4045     TALER_TESTING_cmd_merchant_post_orders_v1 (
   4046       "create-dd96-v1-free",
   4047       merchant_url,
   4048       MHD_HTTP_OK,
   4049       "dd96-v1-free",
   4050       GNUNET_TIME_UNIT_ZERO_TS,
   4051       GNUNET_TIME_UNIT_FOREVER_TS,
   4052       "[{\"amount\":\"EUR:0\",\"inputs\":[],\"outputs\":[]},"
   4053       " {\"amount\":\"EUR:0\",\"inputs\":[],\"outputs\":[]}]"),
   4054     /* the backend must not pick a choice on its own */
   4055     TALER_TESTING_cmd_merchant_collect_order ("collect-dd96-v1-no-choice",
   4056                                               merchant_url,
   4057                                               "dd96-v1-free",
   4058                                               NULL,
   4059                                               -1,
   4060                                               MHD_HTTP_BAD_REQUEST),
   4061     /* nor accept a choice that does not exist */
   4062     TALER_TESTING_cmd_merchant_collect_order ("collect-dd96-v1-oob",
   4063                                               merchant_url,
   4064                                               "dd96-v1-free",
   4065                                               NULL,
   4066                                               7,
   4067                                               MHD_HTTP_BAD_REQUEST),
   4068     /* explicitly selecting a choice collects the order */
   4069     TALER_TESTING_cmd_merchant_collect_order ("collect-dd96-v1-choice1",
   4070                                               merchant_url,
   4071                                               "dd96-v1-free",
   4072                                               "pos-1",
   4073                                               1,
   4074                                               MHD_HTTP_OK),
   4075     /* Re-collecting an order that is already paid, but naming another
   4076        choice, describes a payment that never happened and is refused. */
   4077     TALER_TESTING_cmd_merchant_collect_order ("collect-dd96-v1-other-choice",
   4078                                               merchant_url,
   4079                                               "dd96-v1-free",
   4080                                               "pos-1",
   4081                                               0,
   4082                                               MHD_HTTP_CONFLICT),
   4083     /* ... the order still has to be the one that was actually paid */
   4084     TALER_TESTING_cmd_merchant_check_order_external (
   4085       "check-dd96-v1-choice",
   4086       merchant_url,
   4087       "dd96-v1-free",
   4088       0,
   4089       0,
   4090       1),
   4091     /* record external refunds against the order total of EUR:3 */
   4092     TALER_TESTING_cmd_merchant_refund_external (
   4093       "refund-external-dd96-1",
   4094       merchant_url,
   4095       "dd96-free",
   4096       "{\"method\":\"cash\",\"id\":\"ref1\",\"amount\":\"EUR:0.6\","
   4097       "\"reason\":\"customer return\"}",
   4098       MHD_HTTP_OK),
   4099     /* re-recording the same refund ID with the same body is idempotent
   4100        and must not consume the refundable amount twice */
   4101     TALER_TESTING_cmd_merchant_refund_external (
   4102       "refund-external-dd96-1-again",
   4103       merchant_url,
   4104       "dd96-free",
   4105       "{\"method\":\"cash\",\"id\":\"ref1\",\"amount\":\"EUR:0.6\","
   4106       "\"reason\":\"customer return\"}",
   4107       MHD_HTTP_OK),
   4108     /* the same refund ID with different details is a conflict */
   4109     TALER_TESTING_cmd_merchant_refund_external (
   4110       "refund-external-dd96-1-conflict",
   4111       merchant_url,
   4112       "dd96-free",
   4113       "{\"method\":\"cash\",\"id\":\"ref1\",\"amount\":\"EUR:0.5\","
   4114       "\"reason\":\"customer return\"}",
   4115       MHD_HTTP_CONFLICT),
   4116     /* refund through a different method than the payment; without an
   4117        explicit ID the backend assigns one */
   4118     TALER_TESTING_cmd_merchant_refund_external (
   4119       "refund-external-dd96-2",
   4120       merchant_url,
   4121       "dd96-free",
   4122       "{\"method\":\"card\",\"id\":\"r1\",\"payment_id\":\"cash1\",\"amount\":\"EUR:2.4\","
   4123       "\"reason\":\"customer return\"}",
   4124       MHD_HTTP_OK),
   4125     /* exceeding the order total must be rejected */
   4126     TALER_TESTING_cmd_merchant_refund_external (
   4127       "refund-external-dd96-over",
   4128       merchant_url,
   4129       "dd96-free",
   4130       "{\"method\":\"cash\",\"id\":\"r2\",\"amount\":\"EUR:0.5\","
   4131       "\"reason\":\"customer return\"}",
   4132       MHD_HTTP_CONFLICT),
   4133     /* wrong currency must be rejected */
   4134     TALER_TESTING_cmd_merchant_refund_external (
   4135       "refund-external-dd96-currency",
   4136       merchant_url,
   4137       "dd96-free",
   4138       "{\"method\":\"cash\",\"id\":\"r3\",\"amount\":\"USD:0.5\","
   4139       "\"reason\":\"customer return\"}",
   4140       MHD_HTTP_CONFLICT),
   4141     /* method "taler" must be rejected */
   4142     TALER_TESTING_cmd_merchant_refund_external (
   4143       "refund-external-dd96-taler",
   4144       merchant_url,
   4145       "dd96-free",
   4146       "{\"method\":\"taler\",\"id\":\"r4\",\"amount\":\"EUR:0.5\","
   4147       "\"reason\":\"customer return\"}",
   4148       MHD_HTTP_BAD_REQUEST),
   4149     /* The order status must report the external payment it was settled
   4150        with and the two external refunds that were accepted for it; the
   4151        replayed and the rejected requests must not have added entries. */
   4152     TALER_TESTING_cmd_merchant_check_order_external (
   4153       "check-dd96-free-external",
   4154       merchant_url,
   4155       "dd96-free",
   4156       1,
   4157       2,
   4158       -1),
   4159     /* The combined refund cap must also hold when an external refund is
   4160        followed by an increase of the Taler refund. */
   4161     TALER_TESTING_cmd_merchant_post_orders (
   4162       "create-dd96-taler-refund-cap",
   4163       cred.cfg,
   4164       merchant_url,
   4165       MHD_HTTP_OK,
   4166       "dd96-taler-refund-cap",
   4167       GNUNET_TIME_UNIT_ZERO_TS,
   4168       GNUNET_TIME_UNIT_FOREVER_TS,
   4169       "EUR:5"),
   4170     TALER_TESTING_cmd_merchant_pay_order (
   4171       "pay-dd96-taler-refund-cap",
   4172       merchant_url,
   4173       MHD_HTTP_OK,
   4174       "create-dd96-taler-refund-cap",
   4175       "withdraw-coin-2r",
   4176       "EUR:5",
   4177       "EUR:4.99",
   4178       NULL),
   4179     TALER_TESTING_cmd_merchant_order_refund (
   4180       "refund-taler-dd96-cap-1",
   4181       merchant_url,
   4182       "customer return",
   4183       "dd96-taler-refund-cap",
   4184       "EUR:1",
   4185       MHD_HTTP_OK),
   4186     TALER_TESTING_cmd_merchant_refund_external (
   4187       "refund-external-dd96-cap-3",
   4188       merchant_url,
   4189       "dd96-taler-refund-cap",
   4190       "{\"method\":\"cash\",\"id\":\"r5\",\"amount\":\"EUR:3\","
   4191       "\"reason\":\"returned in cash\"}",
   4192       MHD_HTTP_OK),
   4193     /* A Taler refund of EUR:3 would make the combined refund EUR:6
   4194        for an order whose total is only EUR:5. */
   4195     TALER_TESTING_cmd_merchant_order_refund (
   4196       "refund-taler-dd96-cap-over",
   4197       merchant_url,
   4198       "customer return",
   4199       "dd96-taler-refund-cap",
   4200       "EUR:3",
   4201       MHD_HTTP_CONFLICT),
   4202     /* external refunds also work on pure-Taler orders, e.g. for
   4203        bookkeeping cash returns after the Taler refund deadline;
   4204        order "1r" was paid with EUR:5 and refunded EUR:1 via Taler,
   4205        leaving EUR:4 that may still be refunded externally */
   4206     TALER_TESTING_cmd_merchant_refund_external (
   4207       "refund-external-dd96-taler-order",
   4208       merchant_url,
   4209       "1r",
   4210       "{\"method\":\"cash\",\"id\":\"r6\",\"amount\":\"EUR:3.5\","
   4211       "\"reason\":\"returned in cash after refund deadline\"}",
   4212       MHD_HTTP_OK),
   4213     /* ... but the combined cap still holds: 1 + 3.5 + 1 > 5 */
   4214     TALER_TESTING_cmd_merchant_refund_external (
   4215       "refund-external-dd96-taler-order-over",
   4216       merchant_url,
   4217       "1r",
   4218       "{\"method\":\"cash\",\"id\":\"r7\",\"amount\":\"EUR:1\","
   4219       "\"reason\":\"returned in cash after refund deadline\"}",
   4220       MHD_HTTP_CONFLICT),
   4221     /* unpaid orders must be rejected */
   4222     TALER_TESTING_cmd_merchant_refund_external (
   4223       "refund-external-dd96-unpaid",
   4224       merchant_url,
   4225       "dd96-claimed",
   4226       "{\"method\":\"cash\",\"id\":\"r8\",\"amount\":\"EUR:0.5\","
   4227       "\"reason\":\"customer return\"}",
   4228       MHD_HTTP_CONFLICT),
   4229     /* unknown orders must be rejected */
   4230     TALER_TESTING_cmd_merchant_refund_external (
   4231       "refund-external-dd96-nx",
   4232       merchant_url,
   4233       "dd96-nx",
   4234       "{\"method\":\"cash\",\"id\":\"r9\",\"amount\":\"EUR:0.5\","
   4235       "\"reason\":\"customer return\"}",
   4236       MHD_HTTP_NOT_FOUND),
   4237     TALER_TESTING_cmd_end ()
   4238   };
   4239 
   4240   struct TALER_TESTING_Command commands[] = {
   4241     /* general setup */
   4242     TALER_TESTING_cmd_run_fakebank (
   4243       "run-fakebank",
   4244       cred.cfg,
   4245       "exchange-account-exchange"),
   4246     TALER_TESTING_cmd_system_start (
   4247       "start-taler",
   4248       config_file,
   4249       "-emaD",
   4250       /* The webhook commands below drain the queue with one-shot workers. */
   4251       "-H",
   4252       "-u", "exchange-account-exchange",
   4253       "-r", "merchant-exchange-test",
   4254       NULL),
   4255     TALER_TESTING_cmd_get_exchange (
   4256       "get-exchange",
   4257       cred.cfg,
   4258       NULL,
   4259       true,
   4260       true),
   4261     TALER_TESTING_cmd_batch (
   4262       "orders-id",
   4263       get_private_order_id),
   4264     TALER_TESTING_cmd_config (
   4265       "config",
   4266       merchant_url,
   4267       MHD_HTTP_OK),
   4268     TALER_TESTING_cmd_merchant_get_instances (
   4269       "instances-empty",
   4270       merchant_url,
   4271       MHD_HTTP_OK,
   4272       NULL),
   4273     TALER_TESTING_cmd_merchant_post_instances (
   4274       "instance-create-default-setup",
   4275       merchant_url,
   4276       "admin",
   4277       MHD_HTTP_NO_CONTENT),
   4278     TALER_TESTING_cmd_merchant_post_account (
   4279       "instance-create-default-account",
   4280       merchant_url,
   4281       merchant_payto,
   4282       NULL, NULL,
   4283       MHD_HTTP_OK),
   4284     TALER_TESTING_cmd_merchant_post_instances (
   4285       "instance-create-i1",
   4286       merchant_url,
   4287       "i1",
   4288       MHD_HTTP_NO_CONTENT),
   4289     TALER_TESTING_cmd_merchant_get_instances (
   4290       "instances-get-i1",
   4291       merchant_url,
   4292       MHD_HTTP_OK,
   4293       "instance-create-i1",
   4294       "instance-create-default-setup",
   4295       NULL),
   4296     TALER_TESTING_cmd_merchant_get_instance (
   4297       "instances-get-i1",
   4298       merchant_url,
   4299       "i1",
   4300       MHD_HTTP_OK,
   4301       "instance-create-i1"),
   4302     TALER_TESTING_cmd_merchant_patch_instance (
   4303       "instance-patch-i1",
   4304       merchant_url,
   4305       "i1",
   4306       "bob-the-merchant",
   4307       json_pack ("{s:s}",
   4308                  "street",
   4309                  "bobstreet"),
   4310       json_pack ("{s:s}",
   4311                  "street",
   4312                  "bobjuryst"),
   4313       true,
   4314       GNUNET_TIME_UNIT_ZERO, /* wire transfer */
   4315       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
   4316                                      2), /* small pay delay */
   4317       MHD_HTTP_NO_CONTENT),
   4318     TALER_TESTING_cmd_merchant_get_instance (
   4319       "instances-get-i1-2",
   4320       merchant_url,
   4321       "i1",
   4322       MHD_HTTP_OK,
   4323       "instance-patch-i1"),
   4324     TALER_TESTING_cmd_merchant_get_instance (
   4325       "instances-get-i2-nx",
   4326       merchant_url,
   4327       "i2",
   4328       MHD_HTTP_NOT_FOUND,
   4329       NULL),
   4330     TALER_TESTING_cmd_merchant_post_instances2 (
   4331       "instance-create-ACL",
   4332       merchant_url,
   4333       "i-acl",
   4334       "controlled instance",
   4335       json_pack ("{s:s}", "city",
   4336                  "shopcity"),
   4337       json_pack ("{s:s}", "city",
   4338                  "lawyercity"),
   4339       true,
   4340       GNUNET_TIME_UNIT_ZERO, /* wire transfer */
   4341       GNUNET_TIME_UNIT_SECONDS, /* pay delay */
   4342       // FIXME: change this back once
   4343       // we have a update auth test CMD
   4344       // RFC_8959_PREFIX "EXAMPLE",
   4345       NULL,
   4346       MHD_HTTP_NO_CONTENT),
   4347     TALER_TESTING_cmd_merchant_patch_instance (
   4348       "instance-patch-ACL",
   4349       merchant_url,
   4350       "i-acl",
   4351       "controlled instance",
   4352       json_pack ("{s:s}",
   4353                  "street",
   4354                  "bobstreet"),
   4355       json_pack ("{s:s}",
   4356                  "street",
   4357                  "bobjuryst"),
   4358       true,
   4359       GNUNET_TIME_UNIT_ZERO, /* wire transfer */
   4360       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
   4361                                      2), /* small pay delay */
   4362       MHD_HTTP_NO_CONTENT),
   4363     TALER_TESTING_cmd_merchant_post_instances (
   4364       "instance-create-i2",
   4365       merchant_url,
   4366       "i2",
   4367       MHD_HTTP_NO_CONTENT),
   4368     TALER_TESTING_cmd_merchant_post_instances (
   4369       "instance-create-i2-idem",
   4370       merchant_url,
   4371       "i2",
   4372       MHD_HTTP_NO_CONTENT),
   4373     TALER_TESTING_cmd_merchant_delete_instance (
   4374       "instance-delete-i2",
   4375       merchant_url,
   4376       "i2",
   4377       MHD_HTTP_NO_CONTENT),
   4378     TALER_TESTING_cmd_merchant_get_instance (
   4379       "instances-get-i2-post-deletion",
   4380       merchant_url,
   4381       "i2",
   4382       MHD_HTTP_NOT_FOUND,
   4383       NULL),
   4384     TALER_TESTING_cmd_merchant_purge_instance (
   4385       "instance-delete-then-purge-i2",
   4386       merchant_url,
   4387       "i2",
   4388       MHD_HTTP_NO_CONTENT),
   4389     TALER_TESTING_cmd_merchant_purge_instance (
   4390       "instance-purge-i1",
   4391       merchant_url,
   4392       "i1",
   4393       MHD_HTTP_NO_CONTENT),
   4394     TALER_TESTING_cmd_merchant_delete_instance (
   4395       "instance-purge-then-delete-i1",
   4396       merchant_url,
   4397       "i1",
   4398       MHD_HTTP_NOT_FOUND),
   4399     TALER_TESTING_cmd_merchant_purge_instance (
   4400       "instance-purge-i-acl-middle",
   4401       merchant_url,
   4402       "i-acl",
   4403       MHD_HTTP_NO_CONTENT),
   4404     TALER_TESTING_cmd_merchant_purge_instance (
   4405       "instance-purge-default-middle",
   4406       merchant_url,
   4407       "admin",
   4408       MHD_HTTP_NO_CONTENT),
   4409     TALER_TESTING_cmd_merchant_post_instances (
   4410       "instance-create-default-after-purge",
   4411       merchant_url,
   4412       "admin",
   4413       MHD_HTTP_NO_CONTENT),
   4414     TALER_TESTING_cmd_merchant_post_account (
   4415       "instance-create-default-account-after-purge",
   4416       merchant_url,
   4417       merchant_payto,
   4418       NULL, NULL,
   4419       MHD_HTTP_OK),
   4420     TALER_TESTING_cmd_merchant_get_products (
   4421       "get-products-empty",
   4422       merchant_url,
   4423       MHD_HTTP_OK,
   4424       NULL),
   4425     TALER_TESTING_cmd_merchant_post_products (
   4426       "post-products-p1",
   4427       merchant_url,
   4428       "product-1",
   4429       "a product",
   4430       "EUR:1",
   4431       MHD_HTTP_NO_CONTENT),
   4432     TALER_TESTING_cmd_merchant_post_products (
   4433       "post-products-p1-idem",
   4434       merchant_url,
   4435       "product-1",
   4436       "a product",
   4437       "EUR:1",
   4438       MHD_HTTP_NO_CONTENT),
   4439     TALER_TESTING_cmd_merchant_post_products (
   4440       "post-products-p1-non-idem",
   4441       merchant_url,
   4442       "product-1",
   4443       "a different product",
   4444       "EUR:1",
   4445       MHD_HTTP_CONFLICT),
   4446     TALER_TESTING_cmd_merchant_get_products (
   4447       "get-products-p1",
   4448       merchant_url,
   4449       MHD_HTTP_OK,
   4450       "post-products-p1",
   4451       NULL),
   4452     TALER_TESTING_cmd_merchant_get_product (
   4453       "get-product-p1",
   4454       merchant_url,
   4455       "product-1",
   4456       MHD_HTTP_OK,
   4457       "post-products-p1"),
   4458     TALER_TESTING_cmd_merchant_post_products2 (
   4459       "post-products-img",
   4460       merchant_url,
   4461       "product-img",
   4462       "product with image",
   4463       json_pack ("{s:s}", "en", "product with image"),
   4464       "test-unit",
   4465       "EUR:1",
   4466       "data:image/jpeg;base64,RAWDATA",
   4467       json_array (),
   4468       4,
   4469       0,
   4470       json_pack ("{s:s}", "street", "my street"),
   4471       GNUNET_TIME_UNIT_ZERO_TS,
   4472       MHD_HTTP_NO_CONTENT),
   4473     TALER_TESTING_cmd_get_product_image (
   4474       "get-product-image-img",
   4475       merchant_url,
   4476       "post-products-img",
   4477       "5831ca012639a29df949c3b1e5cd436bac0a5b26a5340ccd95df394b7a8742d6",
   4478       MHD_HTTP_OK),
   4479     TALER_TESTING_cmd_get_product_image (
   4480       "get-product-image-invalid",
   4481       merchant_url,
   4482       NULL,
   4483       "not-a-valid-hash",
   4484       MHD_HTTP_BAD_REQUEST),
   4485     TALER_TESTING_cmd_get_product_image (
   4486       "get-product-image-empty",
   4487       merchant_url,
   4488       NULL,
   4489       "",
   4490       MHD_HTTP_BAD_REQUEST),
   4491     TALER_TESTING_cmd_get_product_image (
   4492       "get-product-image-not-found",
   4493       merchant_url,
   4494       NULL,
   4495       "5831ca012639a29df949c3b1e5cd436bac0a5b26a5340ccd95df394b7a8742d7",
   4496       MHD_HTTP_NOT_FOUND),
   4497     TALER_TESTING_cmd_merchant_post_products (
   4498       "post-products-p2",
   4499       merchant_url,
   4500       "product-2",
   4501       "a product",
   4502       "EUR:1",
   4503       MHD_HTTP_NO_CONTENT),
   4504     TALER_TESTING_cmd_merchant_patch_product (
   4505       "patch-products-p2",
   4506       merchant_url,
   4507       "product-2",
   4508       "another product",
   4509       json_pack ("{s:s}", "en", "text"),
   4510       "kg",
   4511       "EUR:1",
   4512       "data:image/jpeg;base64,RAWDATA",
   4513       json_array (),
   4514       40,
   4515       0,
   4516       json_pack ("{s:s}",
   4517                  "street",
   4518                  "pstreet"),
   4519       GNUNET_TIME_relative_to_timestamp (
   4520         GNUNET_TIME_UNIT_MINUTES),
   4521       MHD_HTTP_NO_CONTENT),
   4522     TALER_TESTING_cmd_merchant_get_product (
   4523       "get-product-p2",
   4524       merchant_url,
   4525       "product-2",
   4526       MHD_HTTP_OK,
   4527       "patch-products-p2"),
   4528     TALER_TESTING_cmd_merchant_get_product (
   4529       "get-product-nx",
   4530       merchant_url,
   4531       "product-nx",
   4532       MHD_HTTP_NOT_FOUND,
   4533       NULL),
   4534     TALER_TESTING_cmd_merchant_patch_product (
   4535       "patch-products-p3-nx",
   4536       merchant_url,
   4537       "product-3",
   4538       "nx updated product",
   4539       json_pack ("{s:s}", "en", "text"),
   4540       "kg",
   4541       "EUR:1",
   4542       "data:image/jpeg;base64,RAWDATA",
   4543       json_array (),
   4544       40,
   4545       0,
   4546       json_pack ("{s:s}",
   4547                  "street",
   4548                  "pstreet"),
   4549       GNUNET_TIME_relative_to_timestamp (
   4550         GNUNET_TIME_UNIT_MINUTES),
   4551       MHD_HTTP_NOT_FOUND),
   4552     TALER_TESTING_cmd_merchant_delete_product (
   4553       "get-products-empty",
   4554       merchant_url,
   4555       "p1",
   4556       MHD_HTTP_NOT_FOUND),
   4557     TALER_TESTING_cmd_merchant_delete_product (
   4558       "get-products-empty",
   4559       merchant_url,
   4560       "product-1",
   4561       MHD_HTTP_NO_CONTENT),
   4562     TALER_TESTING_cmd_merchant_lock_product (
   4563       "lock-product-p2",
   4564       merchant_url,
   4565       "product-2",
   4566       GNUNET_TIME_UNIT_MINUTES,
   4567       2,
   4568       MHD_HTTP_NO_CONTENT),
   4569     TALER_TESTING_cmd_merchant_lock_product (
   4570       "lock-product-nx",
   4571       merchant_url,
   4572       "product-nx",
   4573       GNUNET_TIME_UNIT_MINUTES,
   4574       2,
   4575       MHD_HTTP_NOT_FOUND),
   4576     TALER_TESTING_cmd_merchant_lock_product (
   4577       "lock-product-too-much",
   4578       merchant_url,
   4579       "product-2",
   4580       GNUNET_TIME_UNIT_MINUTES,
   4581       39,
   4582       MHD_HTTP_GONE),
   4583     TALER_TESTING_cmd_merchant_delete_product (
   4584       "delete-product-locked",
   4585       merchant_url,
   4586       "product-2",
   4587       MHD_HTTP_CONFLICT),
   4588     TALER_TESTING_cmd_batch ("pay",
   4589                              pay),
   4590     TALER_TESTING_cmd_batch ("double-spending",
   4591                              double_spending),
   4592     TALER_TESTING_cmd_batch ("pay-again",
   4593                              pay_again),
   4594     TALER_TESTING_cmd_batch ("pay-abort",
   4595                              pay_abort),
   4596     TALER_TESTING_cmd_batch ("refund",
   4597                              refund),
   4598     TALER_TESTING_cmd_batch ("templates",
   4599                              templates),
   4600     TALER_TESTING_cmd_batch ("webhooks",
   4601                              webhooks),
   4602     TALER_TESTING_cmd_batch ("inventory-webhooks",
   4603                              inventory_webhooks),
   4604     TALER_TESTING_cmd_batch ("auth",
   4605                              auth),
   4606     TALER_TESTING_cmd_batch ("repurchase",
   4607                              repurchase),
   4608     TALER_TESTING_cmd_batch ("tokens",
   4609                              tokens),
   4610     TALER_TESTING_cmd_batch ("donau",
   4611                              donau),
   4612     TALER_TESTING_cmd_batch ("partial-payments",
   4613                              partial_payments),
   4614     TALER_TESTING_cmd_batch ("product-categories",
   4615                              product_categories),
   4616     TALER_TESTING_cmd_merchant_get_statisticsamount ("stats-refund",
   4617                                                      merchant_url,
   4618                                                      "refunds-granted",
   4619                                                      6,
   4620                                                      0,
   4621                                                      MHD_HTTP_OK),
   4622     TALER_TESTING_cmd_merchant_get_statisticscounter ("stats-tokens-issued",
   4623                                                       merchant_url,
   4624                                                       "tokens-issued",
   4625                                                       6,
   4626                                                       1,
   4627                                                       MHD_HTTP_OK),
   4628     TALER_TESTING_cmd_merchant_get_statisticscounter ("stats-tokens-used",
   4629                                                       merchant_url,
   4630                                                       "tokens-used",
   4631                                                       6,
   4632                                                       1,
   4633                                                       MHD_HTTP_OK),
   4634 
   4635     /**
   4636      * End the suite.
   4637      */
   4638     TALER_TESTING_cmd_end ()
   4639   };
   4640 
   4641   TALER_TESTING_run (is,
   4642                      commands);
   4643 }
   4644 
   4645 
   4646 int
   4647 main (int argc,
   4648       char *const *argv)
   4649 {
   4650   {
   4651     char *cipher;
   4652 
   4653     cipher = GNUNET_STRINGS_get_suffix_from_binary_name (argv[0]);
   4654     GNUNET_assert (NULL != cipher);
   4655     GNUNET_asprintf (&config_file,
   4656                      "test_merchant_api-%s.conf",
   4657                      cipher);
   4658     GNUNET_free (cipher);
   4659   }
   4660   payer_payto.full_payto =
   4661     (char *) "payto://x-taler-bank/localhost/" USER_ACCOUNT_NAME
   4662     "?receiver-name=" USER_ACCOUNT_NAME;
   4663   exchange_payto.full_payto =
   4664     (char *) "payto://x-taler-bank/localhost/" EXCHANGE_ACCOUNT_NAME
   4665     "?receiver-name="
   4666     EXCHANGE_ACCOUNT_NAME;
   4667   merchant_payto.full_payto =
   4668     (char *) "payto://x-taler-bank/localhost/" MERCHANT_ACCOUNT_NAME
   4669     "?receiver-name=" MERCHANT_ACCOUNT_NAME;
   4670   merchant_url = "http://localhost:8080/";
   4671   GNUNET_asprintf (&merchant_url_i1a,
   4672                    "%sinstances/i1a/",
   4673                    merchant_url);
   4674   return TALER_TESTING_main (argv,
   4675                              "INFO",
   4676                              config_file,
   4677                              "exchange-account-exchange",
   4678                              TALER_TESTING_BS_FAKEBANK,
   4679                              &cred,
   4680                              &run,
   4681                              NULL);
   4682 }
   4683 
   4684 
   4685 /* end of test_merchant_api.c */