merchant

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

test_merchant_api.c (192641B)


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