Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2014-2024 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 : /**
21 : * @file testing_api_cmd_post_orders.c
22 : * @brief command to run POST /orders
23 : * @author Marcello Stanisci
24 : */
25 :
26 : #include "platform.h"
27 : #include <gnunet/gnunet_common.h>
28 : #include <gnunet/gnunet_time_lib.h>
29 : #include <jansson.h>
30 : #include <stdint.h>
31 : #include <taler/taler_exchange_service.h>
32 : #include <taler/taler_testing_lib.h>
33 : #include "taler_merchant_service.h"
34 : #include "taler_merchant_testing_lib.h"
35 :
36 : /**
37 : * State for a "POST /orders" CMD.
38 : */
39 : struct OrdersState
40 : {
41 :
42 : /**
43 : * Expected status code.
44 : */
45 : unsigned int http_status;
46 :
47 : /**
48 : * Order id.
49 : */
50 : const char *order_id;
51 :
52 : /**
53 : * Our configuration.
54 : */
55 : const struct GNUNET_CONFIGURATION_Handle *cfg;
56 :
57 : /**
58 : * The order id we expect the merchant to assign (if not NULL).
59 : */
60 : const char *expected_order_id;
61 :
62 : /**
63 : * Contract terms obtained from the backend.
64 : */
65 : json_t *contract_terms;
66 :
67 : /**
68 : * Order submitted to the backend.
69 : */
70 : json_t *order_terms;
71 :
72 : /**
73 : * Contract terms hash code.
74 : */
75 : struct TALER_PrivateContractHashP h_contract_terms;
76 :
77 : /**
78 : * The /orders operation handle.
79 : */
80 : struct TALER_MERCHANT_PostOrdersHandle *po;
81 :
82 : /**
83 : * The (initial) POST /orders/$ID/claim operation handle.
84 : * The logic is such that after an order creation,
85 : * we immediately claim the order.
86 : */
87 : struct TALER_MERCHANT_OrderClaimHandle *och;
88 :
89 : /**
90 : * The nonce.
91 : */
92 : struct GNUNET_CRYPTO_EddsaPublicKey nonce;
93 :
94 : /**
95 : * Whether to generate a claim token.
96 : */
97 : bool make_claim_token;
98 :
99 : /**
100 : * The claim token
101 : */
102 : struct TALER_ClaimTokenP claim_token;
103 :
104 : /**
105 : * URL of the merchant backend.
106 : */
107 : const char *merchant_url;
108 :
109 : /**
110 : * The interpreter state.
111 : */
112 : struct TALER_TESTING_Interpreter *is;
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 payment target for the order
126 : */
127 : const char *payment_target;
128 :
129 : /**
130 : * The products the order is purchasing.
131 : */
132 : const char *products;
133 :
134 : /**
135 : * The locks that the order should release.
136 : */
137 : const char *locks;
138 :
139 : /**
140 : * Should the command also CLAIM the order?
141 : */
142 : bool with_claim;
143 :
144 : /**
145 : * If not NULL, the command should duplicate the request and verify the
146 : * response is the same as in this command.
147 : */
148 : const char *duplicate_of;
149 : };
150 :
151 :
152 : /**
153 : * Offer internal data to other commands.
154 : *
155 : * @param cls closure
156 : * @param[out] ret result (could be anything)
157 : * @param trait name of the trait
158 : * @param index index number of the object to extract.
159 : * @return #GNUNET_OK on success
160 : */
161 : static enum GNUNET_GenericReturnValue
162 428 : orders_traits (void *cls,
163 : const void **ret,
164 : const char *trait,
165 : unsigned int index)
166 : {
167 428 : struct OrdersState *ps = cls;
168 : struct TALER_TESTING_Trait traits[] = {
169 428 : TALER_TESTING_make_trait_order_id (ps->order_id),
170 428 : TALER_TESTING_make_trait_contract_terms (ps->contract_terms),
171 428 : TALER_TESTING_make_trait_order_terms (ps->order_terms),
172 428 : TALER_TESTING_make_trait_h_contract_terms (&ps->h_contract_terms),
173 428 : TALER_TESTING_make_trait_merchant_sig (&ps->merchant_sig),
174 428 : TALER_TESTING_make_trait_merchant_pub (&ps->merchant_pub),
175 428 : TALER_TESTING_make_trait_claim_nonce (&ps->nonce),
176 428 : TALER_TESTING_make_trait_claim_token (&ps->claim_token),
177 428 : TALER_TESTING_trait_end ()
178 : };
179 :
180 428 : return TALER_TESTING_get_trait (traits,
181 : ret,
182 : trait,
183 : index);
184 : }
185 :
186 :
187 : /**
188 : * Used to fill the "orders" CMD state with backend-provided
189 : * values. Also double-checks that the order was correctly
190 : * created.
191 : *
192 : * @param cls closure
193 : * @param ocr response we got
194 : */
195 : static void
196 36 : orders_claim_cb (void *cls,
197 : const struct TALER_MERCHANT_OrderClaimResponse *ocr)
198 : {
199 36 : struct OrdersState *ps = cls;
200 : const char *error_name;
201 : unsigned int error_line;
202 : struct GNUNET_JSON_Specification spec[] = {
203 36 : GNUNET_JSON_spec_fixed_auto ("merchant_pub",
204 : &ps->merchant_pub),
205 36 : GNUNET_JSON_spec_end ()
206 : };
207 :
208 36 : ps->och = NULL;
209 36 : if (ps->http_status != ocr->hr.http_status)
210 : {
211 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
212 : "Expected status %u, got %u\n",
213 : ps->http_status,
214 : ocr->hr.http_status);
215 0 : TALER_TESTING_FAIL (ps->is);
216 : }
217 36 : if (MHD_HTTP_OK != ocr->hr.http_status)
218 : {
219 0 : TALER_TESTING_interpreter_next (ps->is);
220 0 : return;
221 : }
222 72 : ps->contract_terms = json_deep_copy (
223 36 : (json_t *) ocr->details.ok.contract_terms);
224 36 : ps->h_contract_terms = ocr->details.ok.h_contract_terms;
225 36 : ps->merchant_sig = ocr->details.ok.sig;
226 36 : if (GNUNET_OK !=
227 36 : GNUNET_JSON_parse (ps->contract_terms,
228 : spec,
229 : &error_name,
230 : &error_line))
231 : {
232 : char *log;
233 :
234 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
235 : "Parser failed on %s:%u\n",
236 : error_name,
237 : error_line);
238 0 : log = json_dumps (ps->contract_terms,
239 : JSON_INDENT (1));
240 0 : fprintf (stderr,
241 : "%s\n",
242 : log);
243 0 : free (log);
244 0 : TALER_TESTING_FAIL (ps->is);
245 : }
246 36 : TALER_TESTING_interpreter_next (ps->is);
247 : }
248 :
249 :
250 : /**
251 : * Callback that processes the response following a POST /orders. NOTE: no
252 : * contract terms are included here; they need to be taken via the "orders
253 : * lookup" method.
254 : *
255 : * @param cls closure.
256 : * @param por details about the response
257 : */
258 : static void
259 50 : order_cb (void *cls,
260 : const struct TALER_MERCHANT_PostOrdersReply *por)
261 : {
262 50 : struct OrdersState *ps = cls;
263 :
264 50 : ps->po = NULL;
265 50 : if (ps->http_status != por->hr.http_status)
266 : {
267 0 : TALER_TESTING_unexpected_status_with_body (ps->is,
268 : por->hr.http_status,
269 : ps->http_status,
270 : por->hr.reply);
271 0 : TALER_TESTING_interpreter_fail (ps->is);
272 0 : return;
273 : }
274 50 : switch (por->hr.http_status)
275 : {
276 0 : case 0:
277 0 : TALER_LOG_DEBUG ("/orders, expected 0 status code\n");
278 0 : TALER_TESTING_interpreter_next (ps->is);
279 0 : return;
280 40 : case MHD_HTTP_OK:
281 40 : if (NULL != por->details.ok.token)
282 36 : ps->claim_token = *por->details.ok.token;
283 40 : ps->order_id = GNUNET_strdup (por->details.ok.order_id);
284 40 : if ((NULL != ps->expected_order_id) &&
285 34 : (0 != strcmp (por->details.ok.order_id,
286 : ps->expected_order_id)))
287 : {
288 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
289 : "Order id assigned does not match\n");
290 0 : TALER_TESTING_interpreter_fail (ps->is);
291 0 : return;
292 : }
293 40 : if (NULL != ps->duplicate_of)
294 : {
295 : const struct TALER_TESTING_Command *order_cmd;
296 : const struct TALER_ClaimTokenP *prev_token;
297 2 : struct TALER_ClaimTokenP zero_token = {0};
298 :
299 2 : order_cmd = TALER_TESTING_interpreter_lookup_command (
300 : ps->is,
301 : ps->duplicate_of);
302 2 : if (GNUNET_OK !=
303 2 : TALER_TESTING_get_trait_claim_token (order_cmd,
304 : &prev_token))
305 : {
306 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
307 : "Could not fetch previous order claim token\n");
308 0 : TALER_TESTING_interpreter_fail (ps->is);
309 0 : return;
310 : }
311 2 : if (NULL == por->details.ok.token)
312 0 : prev_token = &zero_token;
313 2 : if (0 != GNUNET_memcmp (prev_token,
314 : por->details.ok.token))
315 : {
316 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
317 : "Claim tokens for identical requests do not match\n");
318 0 : TALER_TESTING_interpreter_fail (ps->is);
319 0 : return;
320 : }
321 : }
322 40 : break;
323 4 : case MHD_HTTP_NOT_FOUND:
324 4 : TALER_TESTING_interpreter_next (ps->is);
325 4 : return;
326 2 : case MHD_HTTP_GONE:
327 2 : TALER_TESTING_interpreter_next (ps->is);
328 2 : return;
329 4 : case MHD_HTTP_CONFLICT:
330 4 : TALER_TESTING_interpreter_next (ps->is);
331 4 : return;
332 0 : default:
333 : {
334 0 : char *s = json_dumps (por->hr.reply,
335 : JSON_COMPACT);
336 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
337 : "Unexpected status code from /orders: %u (%d) at %s; JSON: %s\n",
338 : por->hr.http_status,
339 : (int) por->hr.ec,
340 : TALER_TESTING_interpreter_get_current_label (ps->is),
341 : s);
342 0 : free (s);
343 : /**
344 : * Not failing, as test cases are _supposed_
345 : * to create non 200 OK situations.
346 : */
347 0 : TALER_TESTING_interpreter_next (ps->is);
348 : }
349 0 : return;
350 : }
351 :
352 40 : if (! ps->with_claim)
353 : {
354 4 : TALER_TESTING_interpreter_next (ps->is);
355 4 : return;
356 : }
357 36 : if (NULL ==
358 36 : (ps->och = TALER_MERCHANT_order_claim (
359 : TALER_TESTING_interpreter_get_context (ps->is),
360 : ps->merchant_url,
361 : ps->order_id,
362 36 : &ps->nonce,
363 36 : &ps->claim_token,
364 : &orders_claim_cb,
365 : ps)))
366 0 : TALER_TESTING_FAIL (ps->is);
367 : }
368 :
369 :
370 : /**
371 : * Run a "orders" CMD.
372 : *
373 : * @param cls closure.
374 : * @param cmd command currently being run.
375 : * @param is interpreter state.
376 : */
377 : static void
378 24 : orders_run (void *cls,
379 : const struct TALER_TESTING_Command *cmd,
380 : struct TALER_TESTING_Interpreter *is)
381 : {
382 24 : struct OrdersState *ps = cls;
383 :
384 24 : ps->is = is;
385 24 : if (NULL == json_object_get (ps->order_terms,
386 : "order_id"))
387 : {
388 : struct GNUNET_TIME_Absolute now;
389 : char *order_id;
390 :
391 0 : now = GNUNET_TIME_absolute_get_monotonic (ps->cfg);
392 0 : order_id = GNUNET_STRINGS_data_to_string_alloc (
393 : &now,
394 : sizeof (now));
395 0 : GNUNET_assert (0 ==
396 : json_object_set_new (ps->order_terms,
397 : "order_id",
398 : json_string (order_id)));
399 0 : GNUNET_free (order_id);
400 : }
401 24 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
402 24 : &ps->nonce,
403 : sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
404 24 : ps->po = TALER_MERCHANT_orders_post (TALER_TESTING_interpreter_get_context (
405 : is),
406 : ps->merchant_url,
407 24 : ps->order_terms,
408 24 : GNUNET_TIME_UNIT_ZERO,
409 : &order_cb,
410 : ps);
411 24 : GNUNET_assert (NULL != ps->po);
412 24 : }
413 :
414 :
415 : /**
416 : * Run a "orders" CMD.
417 : *
418 : * @param cls closure.
419 : * @param cmd command currently being run.
420 : * @param is interpreter state.
421 : */
422 : static void
423 18 : orders_run2 (void *cls,
424 : const struct TALER_TESTING_Command *cmd,
425 : struct TALER_TESTING_Interpreter *is)
426 : {
427 18 : struct OrdersState *ps = cls;
428 : const json_t *order;
429 18 : char *products_string = GNUNET_strdup (ps->products);
430 18 : char *locks_string = GNUNET_strdup (ps->locks);
431 : char *token;
432 18 : struct TALER_MERCHANT_InventoryProduct *products = NULL;
433 18 : unsigned int products_length = 0;
434 18 : const char **locks = NULL;
435 18 : unsigned int locks_length = 0;
436 :
437 18 : ps->is = is;
438 18 : if (NULL != ps->duplicate_of)
439 : {
440 : const struct TALER_TESTING_Command *order_cmd;
441 : const json_t *ct;
442 :
443 2 : order_cmd = TALER_TESTING_interpreter_lookup_command (
444 : is,
445 : ps->duplicate_of);
446 2 : if (GNUNET_OK !=
447 2 : TALER_TESTING_get_trait_order_terms (order_cmd,
448 : &ct))
449 : {
450 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
451 : "Could not fetch previous order string\n");
452 0 : TALER_TESTING_interpreter_fail (is);
453 0 : return;
454 : }
455 2 : order = (json_t *) ct;
456 : }
457 : else
458 : {
459 16 : if (NULL == json_object_get (ps->order_terms,
460 : "order_id"))
461 : {
462 : struct GNUNET_TIME_Absolute now;
463 : char *order_id;
464 :
465 0 : now = GNUNET_TIME_absolute_get_monotonic (ps->cfg);
466 0 : order_id = GNUNET_STRINGS_data_to_string_alloc (
467 : &now.abs_value_us,
468 : sizeof (now.abs_value_us));
469 0 : GNUNET_assert (0 ==
470 : json_object_set_new (ps->order_terms,
471 : "order_id",
472 : json_string (order_id)));
473 0 : GNUNET_free (order_id);
474 : }
475 16 : order = ps->order_terms;
476 : }
477 18 : if (NULL == order)
478 : {
479 0 : GNUNET_break (0);
480 0 : TALER_TESTING_interpreter_fail (is);
481 0 : return;
482 : }
483 :
484 18 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
485 18 : &ps->nonce,
486 : sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
487 18 : for (token = strtok (products_string, ";");
488 28 : NULL != token;
489 10 : token = strtok (NULL, ";"))
490 : {
491 : char *ctok;
492 : struct TALER_MERCHANT_InventoryProduct pd;
493 :
494 : /* Token syntax is "[product_id]/[quantity]" */
495 10 : ctok = strchr (token, '/');
496 10 : if (NULL != ctok)
497 : {
498 8 : *ctok = '\0';
499 8 : ctok++;
500 8 : if (1 != sscanf (ctok,
501 : "%u",
502 : &pd.quantity))
503 : {
504 0 : GNUNET_break (0);
505 0 : break;
506 : }
507 : }
508 : else
509 : {
510 2 : pd.quantity = 1;
511 : }
512 10 : pd.product_id = token;
513 :
514 10 : GNUNET_array_append (products,
515 : products_length,
516 : pd);
517 : }
518 18 : for (token = strtok (locks_string, ";");
519 20 : NULL != token;
520 2 : token = strtok (NULL, ";"))
521 : {
522 : const struct TALER_TESTING_Command *lock_cmd;
523 : const char *uuid;
524 :
525 2 : lock_cmd = TALER_TESTING_interpreter_lookup_command (
526 : is,
527 : token);
528 :
529 2 : if (GNUNET_OK !=
530 2 : TALER_TESTING_get_trait_lock_uuid (lock_cmd,
531 : &uuid))
532 : {
533 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
534 : "Could not fetch lock uuid\n");
535 0 : TALER_TESTING_interpreter_fail (is);
536 0 : return;
537 : }
538 :
539 2 : GNUNET_array_append (locks,
540 : locks_length,
541 : uuid);
542 : }
543 18 : ps->po = TALER_MERCHANT_orders_post2 (
544 : TALER_TESTING_interpreter_get_context (
545 : is),
546 : ps->merchant_url,
547 : order,
548 18 : GNUNET_TIME_UNIT_ZERO,
549 : ps->payment_target,
550 : products_length,
551 : products,
552 : locks_length,
553 : locks,
554 18 : ps->make_claim_token,
555 : &order_cb,
556 : ps);
557 18 : GNUNET_free (products_string);
558 18 : GNUNET_free (locks_string);
559 18 : GNUNET_array_grow (products,
560 : products_length,
561 : 0);
562 18 : GNUNET_array_grow (locks,
563 : locks_length,
564 : 0);
565 18 : GNUNET_assert (NULL != ps->po);
566 : }
567 :
568 :
569 : /**
570 : * Run a "orders" CMD.
571 : *
572 : * @param cls closure.
573 : * @param cmd command currently being run.
574 : * @param is interpreter state.
575 : */
576 : static void
577 8 : orders_run3 (void *cls,
578 : const struct TALER_TESTING_Command *cmd,
579 : struct TALER_TESTING_Interpreter *is)
580 : {
581 8 : struct OrdersState *ps = cls;
582 : struct GNUNET_TIME_Absolute now;
583 :
584 8 : ps->is = is;
585 8 : now = GNUNET_TIME_absolute_get_monotonic (ps->cfg);
586 8 : if (NULL == json_object_get (ps->order_terms,
587 : "order_id"))
588 : {
589 : char *order_id;
590 :
591 0 : order_id = GNUNET_STRINGS_data_to_string_alloc (
592 : &now,
593 : sizeof (now));
594 0 : GNUNET_assert (0 ==
595 : json_object_set_new (ps->order_terms,
596 : "order_id",
597 : json_string (order_id)));
598 0 : GNUNET_free (order_id);
599 : }
600 :
601 8 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
602 8 : &ps->nonce,
603 : sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
604 8 : ps->po = TALER_MERCHANT_orders_post (TALER_TESTING_interpreter_get_context (
605 : is),
606 : ps->merchant_url,
607 8 : ps->order_terms,
608 8 : GNUNET_TIME_UNIT_ZERO,
609 : &order_cb,
610 : ps);
611 8 : GNUNET_assert (NULL != ps->po);
612 8 : }
613 :
614 :
615 : /**
616 : * Free the state of a "orders" CMD, and possibly
617 : * cancel it if it did not complete.
618 : *
619 : * @param cls closure.
620 : * @param cmd command being freed.
621 : */
622 : static void
623 50 : orders_cleanup (void *cls,
624 : const struct TALER_TESTING_Command *cmd)
625 : {
626 50 : struct OrdersState *ps = cls;
627 :
628 50 : if (NULL != ps->po)
629 : {
630 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
631 : "Command '%s' did not complete (orders put)\n",
632 : cmd->label);
633 0 : TALER_MERCHANT_orders_post_cancel (ps->po);
634 0 : ps->po = NULL;
635 : }
636 :
637 50 : if (NULL != ps->och)
638 : {
639 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
640 : "Command '%s' did not complete (orders lookup)\n",
641 : cmd->label);
642 0 : TALER_MERCHANT_order_claim_cancel (ps->och);
643 0 : ps->och = NULL;
644 : }
645 :
646 50 : json_decref (ps->contract_terms);
647 50 : json_decref (ps->order_terms);
648 50 : GNUNET_free_nz ((void *) ps->order_id);
649 50 : GNUNET_free (ps);
650 50 : }
651 :
652 :
653 : /**
654 : * Mark part of the contract terms as possible to forget.
655 : *
656 : * @param cls pointer to the result of the forget operation.
657 : * @param object_id name of the object to forget.
658 : * @param parent parent of the object at @e object_id.
659 : */
660 : static void
661 200 : mark_forgettable (void *cls,
662 : const char *object_id,
663 : json_t *parent)
664 : {
665 200 : GNUNET_assert (GNUNET_OK ==
666 : TALER_JSON_contract_mark_forgettable (parent,
667 : object_id));
668 200 : }
669 :
670 :
671 : /**
672 : * Constructs the json for a POST order request.
673 : *
674 : * @param order_id the name of the order to add, can be NULL.
675 : * @param refund_deadline the deadline for refunds on this order.
676 : * @param pay_deadline the deadline for payment on this order.
677 : * @param amount the amount this order is for, NULL for v1 orders
678 : * @param[out] order where to write the json string.
679 : */
680 : static void
681 50 : make_order_json (const char *order_id,
682 : struct GNUNET_TIME_Timestamp refund_deadline,
683 : struct GNUNET_TIME_Timestamp pay_deadline,
684 : const char *amount,
685 : json_t **order)
686 : {
687 50 : struct GNUNET_TIME_Timestamp refund = refund_deadline;
688 50 : struct GNUNET_TIME_Timestamp pay = pay_deadline;
689 : json_t *contract_terms;
690 :
691 : /* Include required fields and some dummy objects to test forgetting. */
692 50 : contract_terms = json_pack (
693 : "{s:s, s:s?, s:s?, s:s, s:o, s:o, s:s, s:[{s:s}, {s:s}, {s:s}]}",
694 : "summary", "merchant-lib testcase",
695 : "order_id", order_id,
696 : "amount", amount,
697 : "fulfillment_url", "https://example.com",
698 : "refund_deadline", GNUNET_JSON_from_timestamp (refund),
699 : "pay_deadline", GNUNET_JSON_from_timestamp (pay),
700 : "dummy_obj", "EUR:1.0",
701 : "dummy_array", /* For testing forgetting parts of arrays */
702 : "item", "speakers",
703 : "item", "headphones",
704 : "item", "earbuds");
705 50 : GNUNET_assert (GNUNET_OK ==
706 : TALER_JSON_expand_path (contract_terms,
707 : "$.dummy_obj",
708 : &mark_forgettable,
709 : NULL));
710 50 : GNUNET_assert (GNUNET_OK ==
711 : TALER_JSON_expand_path (contract_terms,
712 : "$.dummy_array[*].item",
713 : &mark_forgettable,
714 : NULL));
715 50 : *order = contract_terms;
716 50 : }
717 :
718 :
719 : struct TALER_TESTING_Command
720 4 : TALER_TESTING_cmd_merchant_post_orders_no_claim (
721 : const char *label,
722 : const char *merchant_url,
723 : unsigned int http_status,
724 : const char *order_id,
725 : struct GNUNET_TIME_Timestamp refund_deadline,
726 : struct GNUNET_TIME_Timestamp pay_deadline,
727 : const char *amount)
728 : {
729 : struct OrdersState *ps;
730 :
731 4 : ps = GNUNET_new (struct OrdersState);
732 4 : make_order_json (order_id,
733 : refund_deadline,
734 : pay_deadline,
735 : amount,
736 : &ps->order_terms);
737 4 : ps->http_status = http_status;
738 4 : ps->expected_order_id = order_id;
739 4 : ps->merchant_url = merchant_url;
740 : {
741 4 : struct TALER_TESTING_Command cmd = {
742 : .cls = ps,
743 : .label = label,
744 : .run = &orders_run,
745 : .cleanup = &orders_cleanup,
746 : .traits = &orders_traits
747 : };
748 :
749 4 : return cmd;
750 : }
751 : }
752 :
753 :
754 : struct TALER_TESTING_Command
755 16 : TALER_TESTING_cmd_merchant_post_orders (
756 : const char *label,
757 : const struct GNUNET_CONFIGURATION_Handle *cfg,
758 : const char *merchant_url,
759 : unsigned int http_status,
760 : const char *order_id,
761 : struct GNUNET_TIME_Timestamp refund_deadline,
762 : struct GNUNET_TIME_Timestamp pay_deadline,
763 : const char *amount)
764 : {
765 : struct OrdersState *ps;
766 :
767 16 : ps = GNUNET_new (struct OrdersState);
768 16 : ps->cfg = cfg;
769 16 : make_order_json (order_id,
770 : refund_deadline,
771 : pay_deadline,
772 : amount,
773 : &ps->order_terms);
774 16 : ps->http_status = http_status;
775 16 : ps->expected_order_id = order_id;
776 16 : ps->merchant_url = merchant_url;
777 16 : ps->with_claim = true;
778 : {
779 16 : struct TALER_TESTING_Command cmd = {
780 : .cls = ps,
781 : .label = label,
782 : .run = &orders_run,
783 : .cleanup = &orders_cleanup,
784 : .traits = &orders_traits
785 : };
786 :
787 16 : return cmd;
788 : }
789 : }
790 :
791 :
792 : struct TALER_TESTING_Command
793 18 : TALER_TESTING_cmd_merchant_post_orders2 (
794 : const char *label,
795 : const struct GNUNET_CONFIGURATION_Handle *cfg,
796 : const char *merchant_url,
797 : unsigned int http_status,
798 : const char *order_id,
799 : struct GNUNET_TIME_Timestamp refund_deadline,
800 : struct GNUNET_TIME_Timestamp pay_deadline,
801 : bool claim_token,
802 : const char *amount,
803 : const char *payment_target,
804 : const char *products,
805 : const char *locks,
806 : const char *duplicate_of)
807 : {
808 : struct OrdersState *ps;
809 :
810 18 : ps = GNUNET_new (struct OrdersState);
811 18 : ps->cfg = cfg;
812 18 : make_order_json (order_id,
813 : refund_deadline,
814 : pay_deadline,
815 : amount,
816 : &ps->order_terms);
817 18 : ps->http_status = http_status;
818 18 : ps->expected_order_id = order_id;
819 18 : ps->merchant_url = merchant_url;
820 18 : ps->payment_target = payment_target;
821 18 : ps->products = products;
822 18 : ps->locks = locks;
823 18 : ps->with_claim = (NULL == duplicate_of);
824 18 : ps->make_claim_token = claim_token;
825 18 : ps->duplicate_of = duplicate_of;
826 : {
827 18 : struct TALER_TESTING_Command cmd = {
828 : .cls = ps,
829 : .label = label,
830 : .run = &orders_run2,
831 : .cleanup = &orders_cleanup,
832 : .traits = &orders_traits
833 : };
834 :
835 18 : return cmd;
836 : }
837 : }
838 :
839 :
840 : struct TALER_TESTING_Command
841 4 : TALER_TESTING_cmd_merchant_post_orders3 (
842 : const char *label,
843 : const struct GNUNET_CONFIGURATION_Handle *cfg,
844 : const char *merchant_url,
845 : unsigned int expected_http_status,
846 : const char *order_id,
847 : struct GNUNET_TIME_Timestamp refund_deadline,
848 : struct GNUNET_TIME_Timestamp pay_deadline,
849 : const char *fulfillment_url,
850 : const char *amount)
851 : {
852 : struct OrdersState *ps;
853 :
854 4 : ps = GNUNET_new (struct OrdersState);
855 4 : ps->cfg = cfg;
856 4 : make_order_json (order_id,
857 : refund_deadline,
858 : pay_deadline,
859 : amount,
860 : &ps->order_terms);
861 4 : GNUNET_assert (0 ==
862 : json_object_set_new (ps->order_terms,
863 : "fulfillment_url",
864 : json_string (fulfillment_url)));
865 4 : ps->http_status = expected_http_status;
866 4 : ps->merchant_url = merchant_url;
867 4 : ps->with_claim = true;
868 : {
869 4 : struct TALER_TESTING_Command cmd = {
870 : .cls = ps,
871 : .label = label,
872 : .run = &orders_run,
873 : .cleanup = &orders_cleanup,
874 : .traits = &orders_traits
875 : };
876 :
877 4 : return cmd;
878 : }
879 : }
880 :
881 :
882 : struct TALER_TESTING_Command
883 8 : TALER_TESTING_cmd_merchant_post_orders_choices (
884 : const char *label,
885 : const struct GNUNET_CONFIGURATION_Handle *cfg,
886 : const char *merchant_url,
887 : unsigned int http_status,
888 : const char *token_family_slug,
889 : unsigned int num_inputs,
890 : unsigned int num_outputs,
891 : const char *order_id,
892 : struct GNUNET_TIME_Timestamp refund_deadline,
893 : struct GNUNET_TIME_Timestamp pay_deadline,
894 : const char *amount)
895 : {
896 : struct OrdersState *ps;
897 : struct TALER_Amount brutto;
898 : json_t *choice;
899 : json_t *choices;
900 : json_t *inputs;
901 : json_t *outputs;
902 :
903 8 : ps = GNUNET_new (struct OrdersState);
904 8 : ps->cfg = cfg;
905 8 : make_order_json (order_id,
906 : refund_deadline,
907 : pay_deadline,
908 : NULL,
909 : &ps->order_terms);
910 8 : GNUNET_assert (GNUNET_OK ==
911 : TALER_string_to_amount (amount,
912 : &brutto));
913 8 : inputs = json_array ();
914 8 : GNUNET_assert (NULL != inputs);
915 8 : GNUNET_assert (0 ==
916 : json_array_append_new (
917 : inputs,
918 : GNUNET_JSON_PACK (
919 : GNUNET_JSON_pack_string ("type",
920 : "token"),
921 : GNUNET_JSON_pack_uint64 ("count",
922 : num_inputs),
923 : GNUNET_JSON_pack_string ("token_family_slug",
924 : token_family_slug)
925 : )));
926 8 : outputs = json_array ();
927 8 : GNUNET_assert (NULL != outputs);
928 8 : GNUNET_assert (0 ==
929 : json_array_append_new (
930 : outputs,
931 : GNUNET_JSON_PACK (
932 : GNUNET_JSON_pack_string ("type",
933 : "token"),
934 : GNUNET_JSON_pack_uint64 ("count",
935 : num_outputs),
936 : GNUNET_JSON_pack_string ("token_family_slug",
937 : token_family_slug)
938 : )));
939 : choice
940 8 : = GNUNET_JSON_PACK (
941 : TALER_JSON_pack_amount ("amount",
942 : &brutto),
943 : GNUNET_JSON_pack_array_steal ("inputs",
944 : inputs),
945 : GNUNET_JSON_pack_array_steal ("outputs",
946 : outputs));
947 8 : choices = json_array ();
948 8 : GNUNET_assert (NULL != choices);
949 8 : GNUNET_assert (0 ==
950 : json_array_append_new (
951 : choices,
952 : choice));
953 8 : GNUNET_assert (0 ==
954 : json_object_set_new (ps->order_terms,
955 : "choices",
956 : choices)
957 : );
958 8 : GNUNET_assert (0 ==
959 : json_object_set_new (ps->order_terms,
960 : "version",
961 : json_integer (1))
962 : );
963 :
964 :
965 8 : ps->http_status = http_status;
966 8 : ps->expected_order_id = order_id;
967 8 : ps->merchant_url = merchant_url;
968 8 : ps->with_claim = true;
969 : {
970 8 : struct TALER_TESTING_Command cmd = {
971 : .cls = ps,
972 : .label = label,
973 : .run = &orders_run3,
974 : .cleanup = &orders_cleanup,
975 : .traits = &orders_traits
976 : };
977 :
978 8 : return cmd;
979 : }
980 : }
|