Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2014-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/testing_api_cmd_refund.c
21 : * @brief Implement the /refund test command, plus other
22 : * corollary commands (?).
23 : * @author Marcello Stanisci
24 : */
25 : #include "platform.h"
26 : #include "taler_json_lib.h"
27 : #include <gnunet/gnunet_curl_lib.h>
28 : #include "taler_testing_lib.h"
29 :
30 :
31 : /**
32 : * State for a "refund" CMD.
33 : */
34 : struct RefundState
35 : {
36 : /**
37 : * Expected HTTP response code.
38 : */
39 : unsigned int expected_response_code;
40 :
41 : /**
42 : * Amount to be refunded.
43 : */
44 : const char *refund_amount;
45 :
46 : /**
47 : * Reference to any command that can provide a coin to refund.
48 : */
49 : const char *coin_reference;
50 :
51 : /**
52 : * Refund transaction identifier.
53 : */
54 : uint64_t refund_transaction_id;
55 :
56 : /**
57 : * Connection to the exchange.
58 : */
59 : struct TALER_EXCHANGE_Handle *exchange;
60 :
61 : /**
62 : * Handle to the refund operation.
63 : */
64 : struct TALER_EXCHANGE_RefundHandle *rh;
65 :
66 : /**
67 : * Interpreter state.
68 : */
69 : struct TALER_TESTING_Interpreter *is;
70 : };
71 :
72 :
73 : /**
74 : * Check the result for the refund request, just check if the
75 : * response code is acceptable.
76 : *
77 : * @param cls closure
78 : * @param hr HTTP response details
79 : * @param exchange_pub public key the exchange
80 : * used for signing @a obj.
81 : * @param exchange_sig actual signature confirming the refund
82 : */
83 : static void
84 0 : refund_cb (void *cls,
85 : const struct TALER_EXCHANGE_HttpResponse *hr,
86 : const struct TALER_ExchangePublicKeyP *exchange_pub,
87 : const struct TALER_ExchangeSignatureP *exchange_sig)
88 : {
89 :
90 0 : struct RefundState *rs = cls;
91 : struct TALER_TESTING_Command *refund_cmd;
92 :
93 0 : refund_cmd = &rs->is->commands[rs->is->ip];
94 0 : rs->rh = NULL;
95 0 : if (rs->expected_response_code != hr->http_status)
96 : {
97 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
98 : "Unexpected response code %u/%d to command %s in %s:%u\n",
99 : hr->http_status,
100 : hr->ec,
101 : refund_cmd->label,
102 : __FILE__,
103 : __LINE__);
104 0 : json_dumpf (hr->reply,
105 : stderr,
106 : 0);
107 0 : TALER_TESTING_interpreter_fail (rs->is);
108 0 : return;
109 : }
110 0 : TALER_TESTING_interpreter_next (rs->is);
111 : }
112 :
113 :
114 : /**
115 : * Run the command.
116 : *
117 : * @param cls closure.
118 : * @param cmd the command to execute.
119 : * @param is the interpreter state.
120 : */
121 : static void
122 0 : refund_run (void *cls,
123 : const struct TALER_TESTING_Command *cmd,
124 : struct TALER_TESTING_Interpreter *is)
125 : {
126 0 : struct RefundState *rs = cls;
127 : const struct TALER_CoinSpendPrivateKeyP *coin_priv;
128 : struct TALER_CoinSpendPublicKeyP coin;
129 : const json_t *contract_terms;
130 : struct TALER_PrivateContractHashP h_contract_terms;
131 : struct TALER_Amount refund_amount;
132 : const struct TALER_MerchantPrivateKeyP *merchant_priv;
133 : const struct TALER_TESTING_Command *coin_cmd;
134 :
135 0 : rs->exchange = is->exchange;
136 0 : rs->is = is;
137 :
138 0 : if (GNUNET_OK !=
139 0 : TALER_string_to_amount (rs->refund_amount,
140 : &refund_amount))
141 : {
142 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
143 : "Failed to parse amount `%s' at %u/%s\n",
144 : rs->refund_amount,
145 : is->ip,
146 : cmd->label);
147 0 : TALER_TESTING_interpreter_fail (is);
148 0 : return;
149 : }
150 0 : coin_cmd = TALER_TESTING_interpreter_lookup_command (is,
151 : rs->coin_reference);
152 0 : if (NULL == coin_cmd)
153 : {
154 0 : GNUNET_break (0);
155 0 : TALER_TESTING_interpreter_fail (is);
156 0 : return;
157 : }
158 0 : if (GNUNET_OK !=
159 0 : TALER_TESTING_get_trait_contract_terms (coin_cmd,
160 : &contract_terms))
161 : {
162 0 : GNUNET_break (0);
163 0 : TALER_TESTING_interpreter_fail (is);
164 0 : return;
165 : }
166 0 : GNUNET_assert (GNUNET_OK ==
167 : TALER_JSON_contract_hash (contract_terms,
168 : &h_contract_terms));
169 :
170 : /* Hunting for a coin .. */
171 0 : if (GNUNET_OK !=
172 0 : TALER_TESTING_get_trait_coin_priv (coin_cmd,
173 : 0,
174 : &coin_priv))
175 : {
176 0 : GNUNET_break (0);
177 0 : TALER_TESTING_interpreter_fail (is);
178 0 : return;
179 : }
180 :
181 0 : GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
182 : &coin.eddsa_pub);
183 0 : if (GNUNET_OK !=
184 0 : TALER_TESTING_get_trait_merchant_priv (coin_cmd,
185 : &merchant_priv))
186 : {
187 0 : GNUNET_break (0);
188 0 : TALER_TESTING_interpreter_fail (is);
189 0 : return;
190 : }
191 0 : rs->rh = TALER_EXCHANGE_refund (rs->exchange,
192 : &refund_amount,
193 : &h_contract_terms,
194 : &coin,
195 : rs->refund_transaction_id,
196 : merchant_priv,
197 : &refund_cb,
198 : rs);
199 0 : GNUNET_assert (NULL != rs->rh);
200 : }
201 :
202 :
203 : /**
204 : * Free the state from a "refund" CMD, and possibly cancel
205 : * a pending operation thereof.
206 : *
207 : * @param cls closure.
208 : * @param cmd the command which is being cleaned up.
209 : */
210 : static void
211 0 : refund_cleanup (void *cls,
212 : const struct TALER_TESTING_Command *cmd)
213 : {
214 0 : struct RefundState *rs = cls;
215 :
216 0 : if (NULL != rs->rh)
217 : {
218 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
219 : "Command %u (%s) did not complete\n",
220 : rs->is->ip,
221 : cmd->label);
222 0 : TALER_EXCHANGE_refund_cancel (rs->rh);
223 0 : rs->rh = NULL;
224 : }
225 0 : GNUNET_free (rs);
226 0 : }
227 :
228 :
229 : struct TALER_TESTING_Command
230 0 : TALER_TESTING_cmd_refund (const char *label,
231 : unsigned int expected_response_code,
232 : const char *refund_amount,
233 : const char *coin_reference)
234 : {
235 : struct RefundState *rs;
236 :
237 0 : rs = GNUNET_new (struct RefundState);
238 0 : rs->expected_response_code = expected_response_code;
239 0 : rs->refund_amount = refund_amount;
240 0 : rs->coin_reference = coin_reference;
241 : {
242 0 : struct TALER_TESTING_Command cmd = {
243 : .cls = rs,
244 : .label = label,
245 : .run = &refund_run,
246 : .cleanup = &refund_cleanup
247 : };
248 :
249 0 : return cmd;
250 : }
251 : }
252 :
253 :
254 : struct TALER_TESTING_Command
255 0 : TALER_TESTING_cmd_refund_with_id (
256 : const char *label,
257 : unsigned int expected_response_code,
258 : const char *refund_amount,
259 : const char *coin_reference,
260 : uint64_t refund_transaction_id)
261 : {
262 : struct RefundState *rs;
263 :
264 0 : rs = GNUNET_new (struct RefundState);
265 0 : rs->expected_response_code = expected_response_code;
266 0 : rs->refund_amount = refund_amount;
267 0 : rs->coin_reference = coin_reference;
268 0 : rs->refund_transaction_id = refund_transaction_id;
269 : {
270 0 : struct TALER_TESTING_Command cmd = {
271 : .cls = rs,
272 : .label = label,
273 : .run = &refund_run,
274 : .cleanup = &refund_cleanup
275 : };
276 :
277 0 : return cmd;
278 : }
279 : }
|