merchant

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

testing_api_cmd_post_using_templates.c (24375B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2022-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/testing_api_cmd_post_using_templates.c
     21  * @brief command to test POST /using-templates
     22  * @author Priscilla HUANG
     23  */
     24 #include "platform.h"
     25 struct PostUsingTemplatesState;
     26 #define TALER_MERCHANT_POST_TEMPLATES_RESULT_CLOSURE struct PostUsingTemplatesState
     27 #define TALER_MERCHANT_POST_ORDERS_CLAIM_RESULT_CLOSURE struct PostUsingTemplatesState
     28 #include <taler/taler_exchange_service.h>
     29 #include <taler/taler_testing_lib.h>
     30 #include "taler/taler_merchant_service.h"
     31 #include "taler/taler_merchant_testing_lib.h"
     32 #include <taler/merchant/post-templates-TEMPLATE_ID.h>
     33 #include <taler/merchant/post-orders-ORDER_ID-claim.h>
     34 
     35 
     36 /**
     37  * State of a "POST /templates" CMD.
     38  */
     39 struct PostUsingTemplatesState
     40 {
     41 
     42   /**
     43    * Handle for a "POST /templates/$TEMPLATE_ID" request.
     44    */
     45   struct TALER_MERCHANT_PostTemplatesHandle *iph;
     46 
     47   /**
     48    * The interpreter state.
     49    */
     50   struct TALER_TESTING_Interpreter *is;
     51 
     52   /**
     53    * The (initial) POST /orders/$ID/claim operation handle.
     54    * The logic is such that after an order creation,
     55    * we immediately claim the order.
     56    */
     57   struct TALER_MERCHANT_PostOrdersClaimHandle *och;
     58 
     59   /**
     60    * Base URL of the merchant serving the request.
     61    */
     62   const char *merchant_url;
     63 
     64   /**
     65    * ID of the using template to run.
     66    */
     67   const char *using_template_id;
     68 
     69   /**
     70    * Summary given by the customer.
     71    */
     72   const char *summary;
     73 
     74   /**
     75    * Amount given by the customer.
     76    */
     77   struct TALER_Amount amount;
     78 
     79   /**
     80    * Raw request body for inventory templates (if set).
     81    */
     82   json_t *details;
     83 
     84   /**
     85    * Label of a command that created the template we should use.
     86    */
     87   const char *template_ref;
     88 
     89   /**
     90    * Order id.
     91    */
     92   char *order_id;
     93 
     94   /**
     95    * The order id we expect the merchant to assign (if not NULL).
     96    */
     97   const char *expected_order_id;
     98 
     99   /**
    100    * Contract terms obtained from the backend.
    101    */
    102   json_t *contract_terms;
    103 
    104   /**
    105    * Order submitted to the backend.
    106    */
    107   json_t *order_terms;
    108 
    109   /**
    110    * Contract terms hash code.
    111    */
    112   struct TALER_PrivateContractHashP h_contract_terms;
    113 
    114   /**
    115    * Merchant signature over the orders.
    116    */
    117   struct TALER_MerchantSignatureP merchant_sig;
    118 
    119   /**
    120    * Merchant public key.
    121    */
    122   struct TALER_MerchantPublicKeyP merchant_pub;
    123 
    124   /**
    125    * The nonce.
    126    */
    127   struct GNUNET_CRYPTO_EddsaPublicKey nonce;
    128 
    129   /**
    130    * The claim token
    131    */
    132   struct TALER_ClaimTokenP claim_token;
    133 
    134   /**
    135    * Pay deadline returned when the template was instantiated.
    136    */
    137   struct GNUNET_TIME_Timestamp pay_deadline;
    138 
    139   /**
    140    * Time when the template instantiation request was started.
    141    */
    142   struct GNUNET_TIME_Absolute request_start;
    143 
    144   /**
    145    * Pay duration configured in the template.
    146    */
    147   struct GNUNET_TIME_Relative pay_duration;
    148 
    149   /**
    150    * Whether @e pay_duration is finite and non-zero and should be checked.
    151    */
    152   bool check_pay_duration;
    153 
    154   /**
    155    * Whether @e pay_duration was explicitly supplied as the expected duration.
    156    */
    157   bool have_expected_pay_duration;
    158 
    159   /**
    160    * Should the command also CLAIM the order?
    161    */
    162   bool with_claim;
    163 
    164   /**
    165    * If not NULL, the command should duplicate the request and verify the
    166    * response is the same as in this command.
    167    */
    168   const char *duplicate_of;
    169 
    170   /**
    171    * Label of command creating/updating OTP device, or NULL.
    172    */
    173   const char *otp_ref;
    174 
    175   /**
    176    * Encoded key for the payment verification.
    177    */
    178   const char *otp_key;
    179 
    180   /**
    181    * Option that add amount of the order
    182    */
    183   const enum TALER_MerchantConfirmationAlgorithm *otp_alg;
    184 
    185   /**
    186    * Expected HTTP response code.
    187    */
    188   unsigned int http_status;
    189 
    190 };
    191 
    192 /**
    193  * Used to fill the "using_template" CMD state with backend-provided
    194  * values.  Also double-checks that the using_template was correctly
    195  * created.
    196  *
    197  * @param cls closure
    198  * @param ocr response we got
    199  */
    200 static void
    201 using_claim_cb (struct PostUsingTemplatesState *tis,
    202                 const struct TALER_MERCHANT_PostOrdersClaimResponse *ocr)
    203 {
    204   const char *error_name;
    205   unsigned int error_line;
    206   struct GNUNET_TIME_Timestamp pay_deadline;
    207   struct GNUNET_JSON_Specification spec[] = {
    208     GNUNET_JSON_spec_fixed_auto ("merchant_pub",
    209                                  &tis->merchant_pub),
    210     GNUNET_JSON_spec_timestamp ("pay_deadline",
    211                                 &pay_deadline),
    212     GNUNET_JSON_spec_end ()
    213   };
    214 
    215   tis->och = NULL;
    216   if (tis->http_status != ocr->hr.http_status)
    217   {
    218     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    219                 "Expected status %u, got %u\n",
    220                 tis->http_status,
    221                 ocr->hr.http_status);
    222     TALER_TESTING_FAIL (tis->is);
    223   }
    224   if (MHD_HTTP_OK != ocr->hr.http_status)
    225   {
    226     TALER_TESTING_interpreter_next (tis->is);
    227     return;
    228   }
    229   tis->contract_terms = json_deep_copy (
    230     (json_t *) ocr->details.ok.contract_terms);
    231   if (GNUNET_OK !=
    232       TALER_JSON_contract_hash (tis->contract_terms,
    233                                 &tis->h_contract_terms))
    234   {
    235     GNUNET_break (0);
    236     TALER_TESTING_FAIL (tis->is);
    237   }
    238   tis->merchant_sig = ocr->details.ok.merchant_sig;
    239   if (GNUNET_OK !=
    240       GNUNET_JSON_parse (tis->contract_terms,
    241                          spec,
    242                          &error_name,
    243                          &error_line))
    244   {
    245     char *log;
    246 
    247     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    248                 "Parser failed on %s:%u\n",
    249                 error_name,
    250                 error_line);
    251     log = json_dumps (tis->contract_terms,
    252                       JSON_INDENT (1));
    253     fprintf (stderr,
    254              "%s\n",
    255              log);
    256     free (log);
    257     TALER_TESTING_FAIL (tis->is);
    258   }
    259   if (GNUNET_TIME_timestamp_cmp (pay_deadline,
    260                                  !=,
    261                                  tis->pay_deadline))
    262   {
    263     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    264                 "Pay deadline in claimed contract does not match template instantiation response\n");
    265     TALER_TESTING_FAIL (tis->is);
    266   }
    267   TALER_TESTING_interpreter_next (tis->is);
    268 }
    269 
    270 
    271 /**
    272  * Callback for a POST /using-templates operation.
    273  *
    274  * @param cls closure for this function
    275  * @param por response being processed
    276  */
    277 static void
    278 post_using_templates_cb (struct PostUsingTemplatesState *tis,
    279                          const struct TALER_MERCHANT_PostTemplatesResponse *por)
    280 {
    281 
    282   tis->iph = NULL;
    283   if (tis->http_status != por->hr.http_status)
    284   {
    285     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    286                 "Unexpected response code %u (%d) to command %s\n",
    287                 por->hr.http_status,
    288                 (int) por->hr.ec,
    289                 TALER_TESTING_interpreter_get_current_label (tis->is));
    290     TALER_TESTING_interpreter_fail (tis->is);
    291     return;
    292   }
    293   if (0 == tis->http_status)
    294   {
    295     TALER_LOG_DEBUG ("/using_templates, expected 0 status code\n");
    296     TALER_TESTING_interpreter_next (tis->is);
    297     return;
    298   }
    299   // check for order
    300   switch (por->hr.http_status)
    301   {
    302   case MHD_HTTP_OK:
    303     tis->pay_deadline = por->details.ok.pay_deadline;
    304     if (tis->check_pay_duration)
    305     {
    306       struct GNUNET_TIME_Absolute earliest;
    307       struct GNUNET_TIME_Absolute latest;
    308 
    309       earliest = GNUNET_TIME_absolute_subtract (
    310         GNUNET_TIME_absolute_add (tis->request_start,
    311                                   tis->pay_duration),
    312         GNUNET_TIME_UNIT_SECONDS);
    313       latest = GNUNET_TIME_absolute_add (
    314         GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
    315                                   tis->pay_duration),
    316         GNUNET_TIME_UNIT_SECONDS);
    317       if ( (GNUNET_TIME_absolute_cmp (tis->pay_deadline.abs_time,
    318                                      <,
    319                                      earliest)) ||
    320            (GNUNET_TIME_absolute_cmp (tis->pay_deadline.abs_time,
    321                                      >,
    322                                      latest)) )
    323       {
    324         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    325                     "Template pay deadline does not match configured pay duration\n");
    326         TALER_TESTING_interpreter_fail (tis->is);
    327         return;
    328       }
    329     }
    330     if (NULL != por->details.ok.token)
    331       tis->claim_token = *por->details.ok.token;
    332     tis->order_id = GNUNET_strdup (por->details.ok.order_id);
    333     if ((NULL != tis->expected_order_id) &&
    334         (0 != strcmp (por->details.ok.order_id,
    335                       tis->expected_order_id)))
    336     {
    337       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    338                   "Order id assigned does not match\n");
    339       TALER_TESTING_interpreter_fail (tis->is);
    340       return;
    341     }
    342     if (NULL != tis->duplicate_of)
    343     {
    344       const struct TALER_TESTING_Command *order_cmd;
    345       const struct TALER_ClaimTokenP *prev_token;
    346       struct TALER_ClaimTokenP zero_token = {0};
    347       const struct TALER_ClaimTokenP *resp_token;
    348 
    349       order_cmd = TALER_TESTING_interpreter_lookup_command (
    350         tis->is,
    351         tis->duplicate_of);
    352       if (GNUNET_OK !=
    353           TALER_TESTING_get_trait_claim_token (order_cmd,
    354                                                &prev_token))
    355       {
    356         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    357                     "Could not fetch previous order claim token\n");
    358         TALER_TESTING_interpreter_fail (tis->is);
    359         return;
    360       }
    361 
    362       resp_token = (NULL != por->details.ok.token)
    363                    ? por->details.ok.token
    364                    : &zero_token;
    365       if (0 != GNUNET_memcmp (prev_token,
    366                               resp_token))
    367       {
    368         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    369                     "Claim tokens for identical requests do not match\n");
    370         TALER_TESTING_interpreter_fail (tis->is);
    371         return;
    372       }
    373     }
    374     break;
    375   case MHD_HTTP_NOT_FOUND:
    376     TALER_TESTING_interpreter_next (tis->is);
    377     return;
    378   case MHD_HTTP_GONE:
    379     TALER_TESTING_interpreter_next (tis->is);
    380     return;
    381   case MHD_HTTP_CONFLICT:
    382     TALER_TESTING_interpreter_next (tis->is);
    383     return;
    384   default:
    385     {
    386       char *s = json_dumps (por->hr.reply,
    387                             JSON_COMPACT);
    388       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    389                   "Unexpected status code from /orders: %u (%d) at %s; JSON: %s\n",
    390                   por->hr.http_status,
    391                   (int) por->hr.ec,
    392                   TALER_TESTING_interpreter_get_current_label (tis->is),
    393                   s);
    394       GNUNET_free (s);
    395       /**
    396        * Not failing, as test cases are _supposed_
    397        * to create non 200 OK situations.
    398        */
    399       TALER_TESTING_interpreter_next (tis->is);
    400     }
    401     return;
    402   }
    403 
    404   if (! tis->with_claim)
    405   {
    406     TALER_TESTING_interpreter_next (tis->is);
    407     return;
    408   }
    409   tis->och = TALER_MERCHANT_post_orders_claim_create (
    410     TALER_TESTING_interpreter_get_context (tis->is),
    411     tis->merchant_url,
    412     tis->order_id,
    413     &tis->nonce);
    414   if (NULL == tis->och)
    415     TALER_TESTING_FAIL (tis->is);
    416   TALER_MERCHANT_post_orders_claim_set_options (
    417     tis->och,
    418     TALER_MERCHANT_post_orders_claim_option_token (
    419       &tis->claim_token));
    420   {
    421     enum TALER_ErrorCode ec;
    422 
    423     ec = TALER_MERCHANT_post_orders_claim_start (tis->och,
    424                                                  &using_claim_cb,
    425                                                  tis);
    426     GNUNET_assert (TALER_EC_NONE == ec);
    427   }
    428 }
    429 
    430 
    431 /**
    432  * Run the "POST /using-templates" CMD.
    433  *
    434  *
    435  * @param cls closure.
    436  * @param cmd command being run now.
    437  * @param is interpreter state.
    438  */
    439 static void
    440 post_using_templates_run (void *cls,
    441                           const struct TALER_TESTING_Command *cmd,
    442                           struct TALER_TESTING_Interpreter *is)
    443 {
    444   struct PostUsingTemplatesState *tis = cls;
    445   const struct TALER_TESTING_Command *ref;
    446   const char *template_id;
    447   const json_t *template_contract;
    448 
    449   tis->is = is;
    450   ref = TALER_TESTING_interpreter_lookup_command (is,
    451                                                   tis->template_ref);
    452   if (GNUNET_OK !=
    453       TALER_TESTING_get_trait_template_id (ref,
    454                                            &template_id))
    455     TALER_TESTING_FAIL (is);
    456   if (GNUNET_OK !=
    457       TALER_TESTING_get_trait_template_contract (ref,
    458                                                  &template_contract))
    459     TALER_TESTING_FAIL (is);
    460   if (tis->have_expected_pay_duration)
    461   {
    462     tis->check_pay_duration
    463       = (! GNUNET_TIME_relative_is_zero (tis->pay_duration)) &&
    464         (! GNUNET_TIME_relative_is_forever (tis->pay_duration));
    465   }
    466   else if (NULL !=
    467            json_object_get (template_contract,
    468                             "pay_duration"))
    469   {
    470     struct GNUNET_JSON_Specification spec[] = {
    471       GNUNET_JSON_spec_relative_time ("pay_duration",
    472                                       &tis->pay_duration),
    473       GNUNET_JSON_spec_end ()
    474     };
    475 
    476     GNUNET_assert (GNUNET_OK ==
    477                    GNUNET_JSON_parse ((json_t *) template_contract,
    478                                       spec,
    479                                       NULL,
    480                                       NULL));
    481     tis->check_pay_duration
    482       = (! GNUNET_TIME_relative_is_zero (tis->pay_duration)) &&
    483         (! GNUNET_TIME_relative_is_forever (tis->pay_duration));
    484   }
    485   if (NULL != tis->otp_ref)
    486   {
    487     ref = TALER_TESTING_interpreter_lookup_command (is,
    488                                                     tis->otp_ref);
    489     if (GNUNET_OK !=
    490         TALER_TESTING_get_trait_otp_key (ref,
    491                                          &tis->otp_key))
    492       TALER_TESTING_FAIL (is);
    493     if (GNUNET_OK !=
    494         TALER_TESTING_get_trait_otp_alg (ref,
    495                                          &tis->otp_alg))
    496       TALER_TESTING_FAIL (is);
    497   }
    498   GNUNET_CRYPTO_random_block (&tis->nonce,
    499                               sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
    500   tis->iph = TALER_MERCHANT_post_templates_create (
    501     TALER_TESTING_interpreter_get_context (is),
    502     tis->merchant_url,
    503     template_id);
    504   GNUNET_assert (NULL != tis->iph);
    505   if (NULL != tis->details)
    506   {
    507     TALER_MERCHANT_post_templates_set_options (
    508       tis->iph,
    509       TALER_MERCHANT_post_templates_option_details (
    510         tis->details));
    511   }
    512   else
    513   {
    514     if (NULL != tis->summary)
    515       TALER_MERCHANT_post_templates_set_options (
    516         tis->iph,
    517         TALER_MERCHANT_post_templates_option_summary (
    518           tis->summary));
    519     if (TALER_amount_is_valid (&tis->amount))
    520       TALER_MERCHANT_post_templates_set_options (
    521         tis->iph,
    522         TALER_MERCHANT_post_templates_option_amount (
    523           &tis->amount));
    524   }
    525   {
    526     enum TALER_ErrorCode ec;
    527 
    528     tis->request_start = GNUNET_TIME_absolute_get ();
    529     ec = TALER_MERCHANT_post_templates_start (tis->iph,
    530                                               &post_using_templates_cb,
    531                                               tis);
    532     GNUNET_assert (TALER_EC_NONE == ec);
    533   }
    534 }
    535 
    536 
    537 /**
    538  * Offers information from the POST /using-templates CMD state to other
    539  * commands.
    540  *
    541  * @param cls closure
    542  * @param[out] ret result (could be anything)
    543  * @param trait name of the trait
    544  * @param index index number of the object to extract.
    545  * @return #GNUNET_OK on success
    546  */
    547 static enum GNUNET_GenericReturnValue
    548 post_using_templates_traits (void *cls,
    549                              const void **ret,
    550                              const char *trait,
    551                              unsigned int index)
    552 {
    553   struct PostUsingTemplatesState *pts = cls;
    554   struct TALER_TESTING_Trait traits[] = {
    555     TALER_TESTING_make_trait_order_id (pts->order_id),
    556     TALER_TESTING_make_trait_contract_terms (pts->contract_terms),
    557     TALER_TESTING_make_trait_order_terms (pts->order_terms),
    558     TALER_TESTING_make_trait_h_contract_terms (&pts->h_contract_terms),
    559     TALER_TESTING_make_trait_merchant_sig (&pts->merchant_sig),
    560     TALER_TESTING_make_trait_merchant_pub (&pts->merchant_pub),
    561     TALER_TESTING_make_trait_claim_nonce (&pts->nonce),
    562     TALER_TESTING_make_trait_claim_token (&pts->claim_token),
    563     TALER_TESTING_make_trait_otp_key (pts->otp_key),
    564     TALER_TESTING_make_trait_otp_alg (pts->otp_alg),
    565     TALER_TESTING_trait_end (),
    566   };
    567 
    568   (void) pts;
    569   return TALER_TESTING_get_trait (traits,
    570                                   ret,
    571                                   trait,
    572                                   index);
    573 }
    574 
    575 
    576 /**
    577  * Free the state of a "POST using-template" CMD, and possibly
    578  * cancel a pending operation thereof.
    579  *
    580  * @param cls closure.
    581  * @param cmd command being run.
    582  */
    583 static void
    584 post_using_templates_cleanup (void *cls,
    585                               const struct TALER_TESTING_Command *cmd)
    586 {
    587   struct PostUsingTemplatesState *tis = cls;
    588 
    589   if (NULL != tis->iph)
    590   {
    591     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    592                 "POST /using-templates operation did not complete\n");
    593     TALER_MERCHANT_post_templates_cancel (tis->iph);
    594   }
    595   json_decref (tis->order_terms);
    596   json_decref (tis->contract_terms);
    597   json_decref (tis->details);
    598   GNUNET_free (tis->order_id);
    599   GNUNET_free (tis);
    600 }
    601 
    602 
    603 /**
    604  * Mark part of the contract terms as possible to forget.
    605  *
    606  * @param cls pointer to the result of the forget operation.
    607  * @param object_id name of the object to forget.
    608  * @param parent parent of the object at @e object_id.
    609  */
    610 static void
    611 mark_forgettable (void *cls,
    612                   const char *object_id,
    613                   json_t *parent)
    614 {
    615   GNUNET_assert (GNUNET_OK ==
    616                  TALER_JSON_contract_mark_forgettable (parent,
    617                                                        object_id));
    618 }
    619 
    620 
    621 /**
    622  * Constructs the json for a POST using template request.
    623  *
    624  * @param using_template_id the name of the using_template to add, can be NULL.
    625  * @param refund_deadline the deadline for refunds on this using template.
    626  * @param pay_deadline the deadline for payment on this using template.
    627  * @param amount the amount this using template is for.
    628  * @param[out] using_template where to write the json string.
    629  */
    630 static void
    631 make_order_json (const char *using_template_id,
    632                  struct GNUNET_TIME_Timestamp refund_deadline,
    633                  struct GNUNET_TIME_Timestamp pay_deadline,
    634                  const char *amount,
    635                  json_t **using_template)
    636 {
    637   struct GNUNET_TIME_Timestamp refund = refund_deadline;
    638   struct GNUNET_TIME_Timestamp pay = pay_deadline;
    639   json_t *contract_terms;
    640   struct TALER_Amount tamount;
    641   json_t *arr;
    642 
    643   if (NULL != amount)
    644     GNUNET_assert (GNUNET_OK ==
    645                    TALER_string_to_amount (amount,
    646                                            &tamount));
    647   /* Include required fields and some dummy objects to test forgetting. */
    648   arr = json_array ();
    649   GNUNET_assert (NULL != arr);
    650   GNUNET_assert (0 ==
    651                  json_array_append_new (
    652                    arr,
    653                    GNUNET_JSON_PACK (
    654                      GNUNET_JSON_pack_string (
    655                        "item", "speakers"))));
    656   GNUNET_assert (0 ==
    657                  json_array_append_new (
    658                    arr,
    659                    GNUNET_JSON_PACK (
    660                      GNUNET_JSON_pack_string (
    661                        "item", "headphones"))));
    662   GNUNET_assert (0 ==
    663                  json_array_append_new (
    664                    arr,
    665                    GNUNET_JSON_PACK (
    666                      GNUNET_JSON_pack_string (
    667                        "item", "earbuds"))));
    668   contract_terms = GNUNET_JSON_PACK (
    669     GNUNET_JSON_pack_string ("summary",
    670                              "merchant-lib testcase"),
    671     GNUNET_JSON_pack_allow_null (
    672       GNUNET_JSON_pack_string (
    673         "using_template_id", using_template_id)),
    674     GNUNET_JSON_pack_conditional (
    675       NULL != amount,
    676       TALER_JSON_pack_amount ("amount",
    677                               &tamount)),
    678     GNUNET_JSON_pack_string ("fulfillment_url",
    679                              "https://example.com"),
    680     GNUNET_JSON_pack_allow_null (
    681       GNUNET_JSON_pack_timestamp ("refund_deadline",
    682                                   refund)),
    683     GNUNET_JSON_pack_allow_null (
    684       GNUNET_JSON_pack_timestamp ("pay_deadline",
    685                                   pay)),
    686     GNUNET_JSON_pack_string ("dummy_obj",
    687                              "EUR:1.0"),
    688     GNUNET_JSON_pack_array_steal ("dummy_array",
    689                                   arr));
    690   GNUNET_assert (GNUNET_OK ==
    691                  TALER_JSON_expand_path (contract_terms,
    692                                          "$.dummy_obj",
    693                                          &mark_forgettable,
    694                                          NULL));
    695   GNUNET_assert (GNUNET_OK ==
    696                  TALER_JSON_expand_path (contract_terms,
    697                                          "$.dummy_array[*].item",
    698                                          &mark_forgettable,
    699                                          NULL));
    700   *using_template = contract_terms;
    701 }
    702 
    703 
    704 struct TALER_TESTING_Command
    705 TALER_TESTING_cmd_merchant_post_using_templates (
    706   const char *label,
    707   const char *template_ref,
    708   const char *otp_ref,
    709   const char *merchant_url,
    710   const char *using_template_id,
    711   const char *summary,
    712   const char *amount,
    713   struct GNUNET_TIME_Timestamp refund_deadline,
    714   struct GNUNET_TIME_Timestamp pay_deadline,
    715   unsigned int http_status)
    716 {
    717   struct PostUsingTemplatesState *tis;
    718 
    719   tis = GNUNET_new (struct PostUsingTemplatesState);
    720   tis->template_ref = template_ref;
    721   tis->otp_ref = otp_ref;
    722   tis->merchant_url = merchant_url;
    723   tis->using_template_id = using_template_id;
    724   tis->http_status = http_status;
    725   tis->summary = summary;
    726   tis->with_claim = true;
    727   make_order_json (using_template_id,
    728                    refund_deadline,
    729                    pay_deadline,
    730                    amount,
    731                    &tis->order_terms);
    732   if (NULL != amount)
    733     GNUNET_assert (GNUNET_OK ==
    734                    TALER_string_to_amount (amount,
    735                                            &tis->amount));
    736   {
    737     struct TALER_TESTING_Command cmd = {
    738       .cls = tis,
    739       .label = label,
    740       .run = &post_using_templates_run,
    741       .cleanup = &post_using_templates_cleanup,
    742       .traits = &post_using_templates_traits
    743     };
    744 
    745     return cmd;
    746   }
    747 }
    748 
    749 
    750 struct TALER_TESTING_Command
    751 TALER_TESTING_cmd_merchant_post_using_templates_with_expected_pay_duration (
    752   const char *label,
    753   const char *template_ref,
    754   const char *otp_ref,
    755   const char *merchant_url,
    756   const char *using_template_id,
    757   const char *summary,
    758   const char *amount,
    759   struct GNUNET_TIME_Timestamp refund_deadline,
    760   struct GNUNET_TIME_Timestamp pay_deadline,
    761   struct GNUNET_TIME_Relative expected_pay_duration,
    762   unsigned int http_status)
    763 {
    764   struct TALER_TESTING_Command cmd;
    765   struct PostUsingTemplatesState *tis;
    766 
    767   cmd = TALER_TESTING_cmd_merchant_post_using_templates (
    768     label,
    769     template_ref,
    770     otp_ref,
    771     merchant_url,
    772     using_template_id,
    773     summary,
    774     amount,
    775     refund_deadline,
    776     pay_deadline,
    777     http_status);
    778   tis = cmd.cls;
    779   tis->pay_duration = expected_pay_duration;
    780   tis->have_expected_pay_duration = true;
    781   return cmd;
    782 }
    783 
    784 
    785 struct TALER_TESTING_Command
    786 TALER_TESTING_cmd_merchant_post_using_templates2 (
    787   const char *label,
    788   const char *template_ref,
    789   const char *otp_ref,
    790   const char *merchant_url,
    791   const char *using_template_id,
    792   const json_t *details,
    793   unsigned int http_status)
    794 {
    795   struct PostUsingTemplatesState *tis;
    796 
    797   tis = GNUNET_new (struct PostUsingTemplatesState);
    798   tis->template_ref = template_ref;
    799   tis->otp_ref = otp_ref;
    800   tis->merchant_url = merchant_url;
    801   tis->using_template_id = using_template_id;
    802   tis->http_status = http_status;
    803   tis->with_claim = true;
    804   if (NULL != details)
    805     tis->details = json_incref ((json_t *) details);
    806   {
    807     struct TALER_TESTING_Command cmd = {
    808       .cls = tis,
    809       .label = label,
    810       .run = &post_using_templates_run,
    811       .cleanup = &post_using_templates_cleanup,
    812       .traits = &post_using_templates_traits
    813     };
    814 
    815     return cmd;
    816   }
    817 }
    818 
    819 
    820 /* end of testing_api_cmd_post_using_templates.c */