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