aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/testing/Makefile.am2
-rw-r--r--src/testing/testing_api_cmd_finish.c240
2 files changed, 241 insertions, 1 deletions
diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am
index 2bb03d157..386fcd041 100644
--- a/src/testing/Makefile.am
+++ b/src/testing/Makefile.am
@@ -42,10 +42,10 @@ libgnunet_test_testing_plugin_testcmd_la_LIBADD = \
42libgnunet_test_testing_plugin_testcmd_la_LDFLAGS = \ 42libgnunet_test_testing_plugin_testcmd_la_LDFLAGS = \
43 $(GN_PLUGIN_LDFLAGS) 43 $(GN_PLUGIN_LDFLAGS)
44 44
45# testing_api_cmd_finish.c
46 45
47libgnunettesting_la_SOURCES = \ 46libgnunettesting_la_SOURCES = \
48 testing_api_cmd_end.c \ 47 testing_api_cmd_end.c \
48 testing_api_cmd_finish.c \
49 testing_api_cmd_local_test_finished.c \ 49 testing_api_cmd_local_test_finished.c \
50 testing_api_cmd_send_peer_ready.c \ 50 testing_api_cmd_send_peer_ready.c \
51 testing_api_cmd_block_until_all_peers_started.c \ 51 testing_api_cmd_block_until_all_peers_started.c \
diff --git a/src/testing/testing_api_cmd_finish.c b/src/testing/testing_api_cmd_finish.c
new file mode 100644
index 000000000..2bcefd803
--- /dev/null
+++ b/src/testing/testing_api_cmd_finish.c
@@ -0,0 +1,240 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet 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 GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file testing/testing_api_cmd_finish.c
22 * @brief command to wait for completion of async command
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27#include "gnunet_testing_ng_lib.h"
28
29/**
30 * Struct to use for command-specific context information closure of a command waiting
31 * for another command.
32 */
33struct FinishState
34{
35 /**
36 * Closure for all commands with command-specific context information.
37 */
38 void *cls;
39
40 /**
41 * Label of the asynchronous command the synchronous command of this closure waits for.
42 */
43 const char *async_label;
44
45 /**
46 * Task for running the finish method of the asynchronous task the command is waiting for.
47 */
48 struct GNUNET_SCHEDULER_Task *finish_task;
49
50 /**
51 * Interpreter we are part of.
52 */
53 struct GNUNET_TESTING_Interpreter *is;
54
55 /**
56 * Function to call when done.
57 */
58 GNUNET_SCHEDULER_TaskCallback cont;
59
60 /**
61 * Closure for @e cont.
62 */
63 void *cont_cls;
64
65 /**
66 * How long to wait until finish fails hard?
67 */
68 struct GNUNET_TIME_Relative timeout;
69
70 /**
71 * Set to #GNUNET_OK if the @a async_label command finished on time
72 */
73 enum GNUNET_GenericReturnValue finished;
74
75};
76
77
78/**
79 */
80static void
81done_finish (void *cls)
82{
83 struct FinishState *finish_state = cls;
84
85 GNUNET_SCHEDULER_cancel (finish_state->finish_task);
86 finish_state->finish_task = NULL;
87 finish_state->finished = GNUNET_YES;
88 if (NULL != finish_state->cont)
89 {
90 finish_state->cont (finish_state->cont_cls);
91 }
92}
93
94
95/**
96 */
97static void
98timeout_finish (void *cls)
99{
100 struct FinishState *finish_state = cls;
101
102 finish_state->finish_task = NULL;
103 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
104 "Timeout waiting for command `%s' to finish\n",
105 finish_state->async_label);
106 finish_state->finished = GNUNET_SYSERR;
107 GNUNET_TESTING_interpreter_fail (finish_state->is);
108}
109
110
111/**
112 * Run method of the command created by the interpreter to wait for another
113 * command to finish.
114 *
115 */
116static void
117run_finish_on_ref (void *cls,
118 struct GNUNET_TESTING_Interpreter *is)
119{
120 struct FinishState *finish_state = cls;
121 const struct GNUNET_TESTING_Command *async_cmd;
122
123 finish_state->is = is;
124 async_cmd
125 = GNUNET_TESTING_interpreter_lookup_command (is,
126 finish_state->async_label);
127 if (NULL == async_cmd)
128 {
129 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
130 "Did not find command `%s'\n",
131 finish_state->async_label);
132 GNUNET_TESTING_interpreter_fail (is);
133 return;
134 }
135 if ( (NULL == async_cmd->finish) ||
136 (! async_cmd->asynchronous_finish) )
137 {
138 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
139 "Cannot finish `%s': not asynchronous\n",
140 finish_state->async_label);
141 GNUNET_TESTING_interpreter_fail (is);
142 return;
143 }
144 finish_state->finish_task
145 = GNUNET_SCHEDULER_add_delayed (finish_state->timeout,
146 &timeout_finish,
147 finish_state);
148 async_cmd->finish (async_cmd->cls,
149 &done_finish,
150 finish_state);
151}
152
153
154/**
155 * Wait for any asynchronous execution of @e run to conclude,
156 * then call finish_cont. Finish may only be called once per command.
157 *
158 * This member may be NULL if this command is a synchronous command,
159 * and also should be set to NULL once the command has finished.
160 *
161 * @param cls closure
162 * @param cont function to call upon completion, can be NULL
163 * @param cont_cls closure for @a cont
164 * @return
165 * #GNUNET_NO if the command is still running and @a cont will be called later
166 * #GNUNET_OK if the command completed successfully and @a cont was called
167 * #GNUNET_SYSERR if the operation @a cont was NOT called
168 */
169static enum GNUNET_GenericReturnValue
170finish_finish_on_ref (void *cls,
171 GNUNET_SCHEDULER_TaskCallback cont,
172 void *cont_cls)
173{
174 struct FinishState *finish_state = cls;
175
176 switch (finish_state->finished)
177 {
178 case GNUNET_OK:
179 cont (cont_cls);
180 break;
181 case GNUNET_SYSERR:
182 GNUNET_break (0);
183 break;
184 case GNUNET_NO:
185 if (NULL != finish_state->cont)
186 {
187 GNUNET_break (0);
188 return GNUNET_SYSERR;
189 }
190 finish_state->cont = cont;
191 finish_state->cont_cls = cont_cls;
192 break;
193 }
194 return finish_state->finished;
195}
196
197
198/**
199 * Create (synchronous) command that waits for another command to finish.
200 * If @a cmd_ref did not finish after @a timeout, this command will fail
201 * the test case.
202 *
203 * @param finish_label label for this command
204 * @param cmd_ref reference to a previous command which we should
205 * wait for (call `finish()` on)
206 * @param timeout how long to wait at most for @a cmd_ref to finish
207 * @return a finish-command.
208 */
209const struct GNUNET_TESTING_Command
210GNUNET_TESTING_cmd_finish (const char *finish_label,
211 const char *cmd_ref,
212 struct GNUNET_TIME_Relative timeout)
213{
214 struct FinishState *finish_state;
215
216 finish_state = GNUNET_new (struct FinishState);
217 finish_state->async_label = cmd_ref;
218 finish_state->timeout = timeout;
219 {
220 struct GNUNET_TESTING_Command cmd = {
221 .cls = finish_state,
222 .label = finish_label,
223 .run = &run_finish_on_ref,
224 .finish = &finish_finish_on_ref
225 };
226
227 return cmd;
228 }
229}
230
231
232struct GNUNET_TESTING_Command
233GNUNET_TESTING_cmd_make_unblocking (struct GNUNET_TESTING_Command cmd)
234{
235 /* do not permit this function to be used on
236 a finish command! */
237 GNUNET_assert (cmd.run != &run_finish_on_ref);
238 cmd.asynchronous_finish = true;
239 return cmd;
240}