Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2020 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify
6 : it under the terms of the GNU General Public License as
7 : published by the Free Software Foundation; either version 3, or
8 : (at your option) any later version.
9 :
10 : TALER is distributed in the hope that it will be useful, but
11 : WITHOUT ANY WARRANTY; without even the implied warranty of
12 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : GNU General Public License for more details.
14 :
15 : You should have received a copy of the GNU General Public
16 : License along with TALER; see the file COPYING. If not, see
17 : <http://www.gnu.org/licenses/>
18 : */
19 : /**
20 : * @file testing_api_cmd_wallet_post_orders_refund.c
21 : * @brief command to test refunds.
22 : * @author Marcello Stanisci
23 : * @author Christian Grothoff
24 : */
25 : #include "platform.h"
26 : #include <taler/taler_exchange_service.h>
27 : #include <taler/taler_testing_lib.h>
28 : #include "taler_merchant_service.h"
29 : #include "taler_merchant_testing_lib.h"
30 :
31 :
32 : /**
33 : * State for an "obtain refunds" CMD.
34 : */
35 : struct WalletRefundState
36 : {
37 : /**
38 : * Operation handle for a (public) POST /orders/$ID/refund request.
39 : */
40 : struct TALER_MERCHANT_WalletOrderRefundHandle *orh;
41 :
42 : /**
43 : * Base URL of the merchant serving the request.
44 : */
45 : const char *merchant_url;
46 :
47 : /**
48 : * Interpreter state.
49 : */
50 : struct TALER_TESTING_Interpreter *is;
51 :
52 : /**
53 : * Expected HTTP response code.
54 : */
55 : unsigned int http_code;
56 :
57 : /**
58 : * Label of the command that created the order we want to obtain refunds for.
59 : */
60 : const char *proposal_reference;
61 :
62 : /**
63 : * A list of refunds associated with this order.
64 : */
65 : const char **refunds;
66 :
67 : /**
68 : * The length of @e refunds.
69 : */
70 : unsigned int refunds_length;
71 : };
72 :
73 :
74 : /**
75 : * Process POST /refund (increase) response; just checking
76 : * if the HTTP response code is the one expected.
77 : *
78 : * @param cls closure
79 : * @param hr HTTP response
80 : * @param refund_amount refund amount
81 : * @param merchant_pub public key of the merchant giving the refund
82 : * @param refunds the given refunds
83 : * @param refunds_length how many refunds were given
84 : */
85 : static void
86 0 : refund_cb (
87 : void *cls,
88 : const struct TALER_MERCHANT_HttpResponse *hr,
89 : const struct TALER_Amount *refund_amount,
90 : const struct TALER_MerchantPublicKeyP *merchant_pub,
91 : struct TALER_MERCHANT_RefundDetail refunds[],
92 : unsigned int refunds_length)
93 : {
94 0 : struct WalletRefundState *wrs = cls;
95 :
96 0 : wrs->orh = NULL;
97 0 : if (wrs->http_code != hr->http_status)
98 : {
99 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
100 : "Expected status %u, got %u(%d) for refund increase\n",
101 : wrs->http_code,
102 : hr->http_status,
103 : (int) hr->ec);
104 0 : TALER_TESTING_FAIL (wrs->is);
105 : }
106 0 : switch (hr->http_status)
107 : {
108 0 : case MHD_HTTP_OK:
109 : {
110 : struct TALER_Amount refunded_total;
111 0 : if (refunds_length > 0)
112 0 : GNUNET_assert (GNUNET_OK ==
113 : TALER_amount_set_zero (refunds[0].refund_amount.currency,
114 : &refunded_total));
115 0 : for (unsigned int i = 0; i < refunds_length; ++i)
116 : {
117 : const struct TALER_TESTING_Command *refund_cmd;
118 : const struct TALER_Amount *expected_amount;
119 :
120 0 : refund_cmd = TALER_TESTING_interpreter_lookup_command (
121 : wrs->is,
122 0 : wrs->refunds[i]);
123 :
124 0 : if (GNUNET_OK !=
125 0 : TALER_TESTING_get_trait_amount (refund_cmd,
126 : &expected_amount))
127 : {
128 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
129 : "Could not fetch refund amount\n");
130 0 : TALER_TESTING_interpreter_fail (wrs->is);
131 0 : return;
132 : }
133 : /* The most recent refunds are returned first */
134 0 : GNUNET_assert (0 <= TALER_amount_add (&refunded_total,
135 : &refunded_total,
136 : &refunds[refunds_length - 1
137 : - i].refund_amount));
138 0 : if ((GNUNET_OK !=
139 0 : TALER_amount_cmp_currency (expected_amount,
140 0 : &refunded_total)) ||
141 0 : (0 != TALER_amount_cmp (expected_amount,
142 : &refunded_total)))
143 : {
144 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
145 : "Refund amounts do not match\n");
146 0 : TALER_TESTING_interpreter_fail (wrs->is);
147 0 : return;
148 : }
149 : }
150 : }
151 0 : break;
152 0 : default:
153 :
154 0 : break;
155 : }
156 0 : TALER_TESTING_interpreter_next (wrs->is);
157 : }
158 :
159 :
160 : /**
161 : * Run the "refund increase" CMD.
162 : *
163 : * @param cls closure.
164 : * @param cmd command currently being run.
165 : * @param is the interpreter state.
166 : */
167 : static void
168 0 : obtain_refunds_run (void *cls,
169 : const struct TALER_TESTING_Command *cmd,
170 : struct TALER_TESTING_Interpreter *is)
171 : {
172 0 : struct WalletRefundState *wrs = cls;
173 : const struct TALER_TESTING_Command *proposal_cmd =
174 0 : TALER_TESTING_interpreter_lookup_command (is,
175 : wrs->proposal_reference);
176 : const struct TALER_PrivateContractHashP *h_contract_terms;
177 : const char *order_id;
178 :
179 0 : if (NULL == proposal_cmd)
180 0 : TALER_TESTING_FAIL (is);
181 0 : if (GNUNET_OK !=
182 0 : TALER_TESTING_get_trait_h_contract_terms (proposal_cmd,
183 : &h_contract_terms))
184 0 : TALER_TESTING_FAIL (is);
185 :
186 : {
187 : const json_t *contract_terms;
188 : const char *error_name;
189 : unsigned int error_line;
190 :
191 0 : if (GNUNET_OK !=
192 0 : TALER_TESTING_get_trait_contract_terms (proposal_cmd,
193 : &contract_terms))
194 0 : TALER_TESTING_FAIL (is);
195 : {
196 : /* Get information that needs to be put verbatim in the
197 : * deposit permission */
198 : struct GNUNET_JSON_Specification spec[] = {
199 0 : GNUNET_JSON_spec_string ("order_id",
200 : &order_id),
201 0 : GNUNET_JSON_spec_end ()
202 : };
203 :
204 0 : if (GNUNET_OK !=
205 0 : GNUNET_JSON_parse (contract_terms,
206 : spec,
207 : &error_name,
208 : &error_line))
209 : {
210 : char *js;
211 :
212 0 : js = json_dumps (contract_terms,
213 : JSON_INDENT (1));
214 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
215 : "Parser failed on %s:%u for input `%s'\n",
216 : error_name,
217 : error_line,
218 : js);
219 0 : free (js);
220 0 : TALER_TESTING_FAIL (is);
221 : }
222 : }
223 : }
224 :
225 0 : wrs->is = is;
226 0 : wrs->orh = TALER_MERCHANT_wallet_post_order_refund (
227 : is->ctx,
228 : wrs->merchant_url,
229 : order_id,
230 : h_contract_terms,
231 : &refund_cb,
232 : wrs);
233 0 : if (NULL == wrs->orh)
234 0 : TALER_TESTING_FAIL (is);
235 : }
236 :
237 :
238 : /**
239 : * Free the state of a "refund increase" CMD, and
240 : * possibly cancel a pending "refund increase" operation.
241 : *
242 : * @param cls closure
243 : * @param cmd command currently being freed.
244 : */
245 : static void
246 0 : obtain_refunds_cleanup (void *cls,
247 : const struct TALER_TESTING_Command *cmd)
248 : {
249 0 : struct WalletRefundState *wrs = cls;
250 :
251 0 : if (NULL != wrs->orh)
252 : {
253 0 : TALER_LOG_WARNING ("Refund operation did not complete\n");
254 0 : TALER_MERCHANT_wallet_post_order_refund_cancel (wrs->orh);
255 : }
256 0 : GNUNET_array_grow (wrs->refunds,
257 : wrs->refunds_length,
258 : 0);
259 0 : GNUNET_free (wrs);
260 0 : }
261 :
262 :
263 : struct TALER_TESTING_Command
264 0 : TALER_TESTING_cmd_wallet_order_refund (const char *label,
265 : const char *merchant_url,
266 : const char *order_ref,
267 : unsigned int http_code,
268 : ...)
269 : {
270 : struct WalletRefundState *wrs;
271 :
272 0 : wrs = GNUNET_new (struct WalletRefundState);
273 0 : wrs->merchant_url = merchant_url;
274 0 : wrs->proposal_reference = order_ref;
275 0 : wrs->http_code = http_code;
276 0 : wrs->refunds_length = 0;
277 : {
278 : const char *clabel;
279 : va_list ap;
280 :
281 0 : va_start (ap, http_code);
282 0 : while (NULL != (clabel = va_arg (ap, const char *)))
283 : {
284 0 : GNUNET_array_append (wrs->refunds,
285 : wrs->refunds_length,
286 : clabel);
287 : }
288 0 : va_end (ap);
289 : }
290 : {
291 0 : struct TALER_TESTING_Command cmd = {
292 : .cls = wrs,
293 : .label = label,
294 : .run = &obtain_refunds_run,
295 : .cleanup = &obtain_refunds_cleanup
296 : };
297 :
298 0 : return cmd;
299 : }
300 : }
|