Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2025 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_get_unit.c
21 : * @brief command to test GET /private/units/$ID
22 : * @author Bohdan Potuzhnyi
23 : */
24 : #include "platform.h"
25 : struct GetUnitState;
26 : #define TALER_MERCHANT_GET_PRIVATE_UNIT_RESULT_CLOSURE struct GetUnitState
27 : #include <jansson.h>
28 : #include <taler/taler_testing_lib.h>
29 : #include "taler/taler_merchant_service.h"
30 : #include "taler/taler_merchant_testing_lib.h"
31 : #include <taler/merchant/get-private-units-UNIT.h>
32 :
33 :
34 : /**
35 : * State for a GET /private/units/$ID command.
36 : */
37 : struct GetUnitState
38 : {
39 : /**
40 : * In-flight request handle.
41 : */
42 : struct TALER_MERCHANT_GetPrivateUnitHandle *ugh;
43 :
44 : /**
45 : * Interpreter context.
46 : */
47 : struct TALER_TESTING_Interpreter *is;
48 :
49 : /**
50 : * Merchant backend base URL.
51 : */
52 : const char *merchant_url;
53 :
54 : /**
55 : * Unit identifier to fetch.
56 : */
57 : const char *unit_id;
58 :
59 : /**
60 : * Expected HTTP status.
61 : */
62 : unsigned int http_status;
63 :
64 : /**
65 : * Optional command label providing expected traits.
66 : */
67 : const char *reference;
68 : };
69 :
70 :
71 : /**
72 : * Compare response @a entry with traits from @a ref_cmd.
73 : */
74 : static bool
75 8 : unit_matches_reference (const struct TALER_MERCHANT_UnitEntry *entry,
76 : const struct TALER_TESTING_Command *ref_cmd)
77 : {
78 : const char *unit_id;
79 :
80 8 : if (GNUNET_OK !=
81 8 : TALER_TESTING_get_trait_unit_id (ref_cmd,
82 : &unit_id))
83 : {
84 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
85 : "Unit trait resolution failed for reference `%s'\n",
86 : ref_cmd->label);
87 0 : return false;
88 : }
89 8 : if (0 != strcmp (entry->unit,
90 : unit_id))
91 : {
92 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
93 : "Unit mismatch: expected id %s got %s\n",
94 : unit_id,
95 : entry->unit);
96 0 : return false;
97 : }
98 :
99 : {
100 8 : const char *unit_name_long = NULL;
101 :
102 8 : if (GNUNET_OK ==
103 8 : TALER_TESTING_get_trait_unit_name_long (ref_cmd,
104 : &unit_name_long))
105 : {
106 8 : if ( (NULL != unit_name_long) &&
107 4 : (0 != strcmp (entry->unit_name_long,
108 : unit_name_long)) )
109 : {
110 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
111 : "Unit %s mismatch: expected long label '%s' got '%s'\n",
112 : entry->unit,
113 : unit_name_long,
114 : entry->unit_name_long);
115 0 : return false;
116 : }
117 : }
118 : }
119 : {
120 8 : const char *unit_name_short = NULL;
121 :
122 8 : if (GNUNET_OK ==
123 8 : TALER_TESTING_get_trait_unit_name_short (ref_cmd,
124 : &unit_name_short))
125 : {
126 8 : if ( (NULL != unit_name_short) &&
127 4 : (0 != strcmp (entry->unit_name_short,
128 : unit_name_short)) )
129 : {
130 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
131 : "Unit %s mismatch: expected short label '%s' got '%s'\n",
132 : entry->unit,
133 : unit_name_short,
134 : entry->unit_name_short);
135 0 : return false;
136 : }
137 : }
138 : }
139 : {
140 8 : const bool *unit_allow_fraction = NULL;
141 :
142 8 : if (GNUNET_OK ==
143 8 : TALER_TESTING_get_trait_unit_allow_fraction (ref_cmd,
144 : &unit_allow_fraction))
145 : {
146 8 : if ( (NULL != unit_allow_fraction) &&
147 8 : (*unit_allow_fraction != entry->unit_allow_fraction) )
148 : {
149 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
150 : "Unit %s mismatch: expected allow_fraction %d got %d\n",
151 : entry->unit,
152 : (int) *unit_allow_fraction,
153 : (int) entry->unit_allow_fraction);
154 0 : return false;
155 : }
156 : }
157 : }
158 : {
159 8 : const uint32_t *unit_precision_level = NULL;
160 :
161 8 : if (GNUNET_OK ==
162 8 : TALER_TESTING_get_trait_unit_precision_level (ref_cmd,
163 : &unit_precision_level))
164 : {
165 8 : if ( (NULL != unit_precision_level) &&
166 8 : (*unit_precision_level != entry->unit_precision_level) )
167 : {
168 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
169 : "Unit %s mismatch: expected precision %u got %u\n",
170 : entry->unit,
171 : (unsigned int) *unit_precision_level,
172 : (unsigned int) entry->unit_precision_level);
173 0 : return false;
174 : }
175 : }
176 : }
177 : {
178 8 : const bool *unit_active = NULL;
179 :
180 8 : if (GNUNET_OK ==
181 8 : TALER_TESTING_get_trait_unit_active (ref_cmd,
182 : &unit_active))
183 : {
184 8 : if ( (NULL != unit_active) &&
185 8 : (*unit_active != entry->unit_active) )
186 : {
187 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
188 : "Unit %s mismatch: expected active flag %d got %d\n",
189 : entry->unit,
190 : (int) *unit_active,
191 : (int) entry->unit_active);
192 0 : return false;
193 : }
194 : }
195 : }
196 : {
197 8 : const json_t *unit_name_long_i18n = NULL;
198 :
199 8 : if (GNUNET_OK ==
200 8 : TALER_TESTING_get_trait_unit_name_long_i18n (ref_cmd,
201 : &unit_name_long_i18n))
202 : {
203 8 : if ( (NULL != unit_name_long_i18n) &&
204 8 : ( (NULL == entry->unit_name_long_i18n) ||
205 4 : (1 != json_equal (unit_name_long_i18n,
206 4 : entry->unit_name_long_i18n)) ) )
207 : {
208 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
209 : "Unit %s mismatch: long_i18n differs\n",
210 : entry->unit);
211 0 : return false;
212 : }
213 : }
214 : }
215 : {
216 8 : const json_t *unit_name_short_i18n = NULL;
217 :
218 8 : if (GNUNET_OK ==
219 8 : TALER_TESTING_get_trait_unit_name_short_i18n (ref_cmd,
220 : &unit_name_short_i18n))
221 : {
222 8 : if ( (NULL != unit_name_short_i18n) &&
223 8 : ( (NULL == entry->unit_name_short_i18n) ||
224 4 : (1 != json_equal (unit_name_short_i18n,
225 4 : entry->unit_name_short_i18n)) ) )
226 : {
227 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
228 : "Unit %s mismatch: short_i18n differs\n",
229 : entry->unit);
230 0 : return false;
231 : }
232 : }
233 : }
234 8 : return true;
235 : }
236 :
237 :
238 : /**
239 : * Completion callback.
240 : */
241 : static void
242 10 : get_unit_cb (struct GetUnitState *gug,
243 : const struct TALER_MERCHANT_GetPrivateUnitResponse *ugr)
244 : {
245 :
246 10 : gug->ugh = NULL;
247 10 : if (gug->http_status != ugr->hr.http_status)
248 : {
249 0 : TALER_TESTING_unexpected_status_with_body (gug->is,
250 : ugr->hr.http_status,
251 : gug->http_status,
252 : ugr->hr.reply);
253 0 : return;
254 : }
255 10 : if ( (MHD_HTTP_OK == ugr->hr.http_status) &&
256 8 : (NULL != gug->reference) )
257 : {
258 : const struct TALER_TESTING_Command *ref_cmd;
259 :
260 8 : ref_cmd = TALER_TESTING_interpreter_lookup_command (gug->is,
261 : gug->reference);
262 8 : if (NULL == ref_cmd)
263 : {
264 0 : GNUNET_break (0);
265 0 : TALER_TESTING_interpreter_fail (gug->is);
266 0 : return;
267 : }
268 8 : if (! unit_matches_reference (&ugr->details.ok.unit,
269 : ref_cmd))
270 : {
271 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
272 : "GET /private/units/%s response does not match expectation from `%s'\n",
273 : gug->unit_id,
274 : gug->reference);
275 0 : TALER_TESTING_interpreter_fail (gug->is);
276 0 : return;
277 : }
278 : }
279 10 : TALER_TESTING_interpreter_next (gug->is);
280 : }
281 :
282 :
283 : /**
284 : * Issue GET request.
285 : */
286 : static void
287 10 : get_unit_run (void *cls,
288 : const struct TALER_TESTING_Command *cmd,
289 : struct TALER_TESTING_Interpreter *is)
290 : {
291 10 : struct GetUnitState *gug = cls;
292 :
293 10 : gug->is = is;
294 10 : gug->ugh = TALER_MERCHANT_get_private_unit_create (
295 : TALER_TESTING_interpreter_get_context (is),
296 : gug->merchant_url,
297 : gug->unit_id);
298 : {
299 : enum TALER_ErrorCode ec;
300 :
301 10 : ec = TALER_MERCHANT_get_private_unit_start (
302 : gug->ugh,
303 : &get_unit_cb,
304 : gug);
305 10 : GNUNET_assert (TALER_EC_NONE == ec);
306 : }
307 10 : }
308 :
309 :
310 : /**
311 : * Cleanup.
312 : */
313 : static void
314 10 : get_unit_cleanup (void *cls,
315 : const struct TALER_TESTING_Command *cmd)
316 : {
317 10 : struct GetUnitState *gug = cls;
318 :
319 10 : if (NULL != gug->ugh)
320 : {
321 0 : TALER_MERCHANT_get_private_unit_cancel (gug->ugh);
322 0 : gug->ugh = NULL;
323 : }
324 10 : GNUNET_free (gug);
325 10 : }
326 :
327 :
328 : struct TALER_TESTING_Command
329 10 : TALER_TESTING_cmd_merchant_get_unit (const char *label,
330 : const char *merchant_url,
331 : const char *unit_id,
332 : unsigned int http_status,
333 : const char *reference)
334 : {
335 : struct GetUnitState *gug;
336 :
337 10 : gug = GNUNET_new (struct GetUnitState);
338 10 : gug->merchant_url = merchant_url;
339 10 : gug->unit_id = unit_id;
340 10 : gug->http_status = http_status;
341 10 : gug->reference = reference;
342 :
343 : {
344 10 : struct TALER_TESTING_Command cmd = {
345 : .cls = gug,
346 : .label = label,
347 : .run = &get_unit_run,
348 : .cleanup = &get_unit_cleanup
349 : };
350 :
351 10 : return cmd;
352 : }
353 : }
354 :
355 :
356 : /* end of testing_api_cmd_get_unit.c */
|