aboutsummaryrefslogtreecommitdiff
path: root/src/testing/testing_api_cmd_finish.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/testing/testing_api_cmd_finish.c')
-rw-r--r--src/testing/testing_api_cmd_finish.c198
1 files changed, 198 insertions, 0 deletions
diff --git a/src/testing/testing_api_cmd_finish.c b/src/testing/testing_api_cmd_finish.c
new file mode 100644
index 000000000..3ac0871a5
--- /dev/null
+++ b/src/testing/testing_api_cmd_finish.c
@@ -0,0 +1,198 @@
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 * Function to call when done.
52 */
53 struct GNUNET_TESTING_AsyncContext ac;
54
55 /**
56 * How long to wait until finish fails hard?
57 */
58 struct GNUNET_TIME_Relative timeout;
59
60};
61
62
63/**
64 * Function called when the command we are waiting on
65 * is finished. Hence we are finished, too.
66 *
67 * @param cls a `struct FinishState` being notified
68 */
69static void
70done_finish (void *cls)
71{
72 struct FinishState *finish_state = cls;
73
74 GNUNET_SCHEDULER_cancel (finish_state->finish_task);
75 finish_state->finish_task = NULL;
76 GNUNET_TESTING_async_finish (&finish_state->ac);
77}
78
79
80/**
81 * Function triggered if the command we are waiting
82 * for did not complete on time.
83 *
84 * @param cls our `struct FinishState`
85 */
86static void
87timeout_finish (void *cls)
88{
89 struct FinishState *finish_state = cls;
90
91 finish_state->finish_task = NULL;
92 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
93 "Timeout waiting for command `%s' to finish\n",
94 finish_state->async_label);
95 GNUNET_TESTING_async_fail (&finish_state->ac);
96}
97
98
99/**
100 * Run method of the command created by the interpreter to wait for another
101 * command to finish.
102 *
103 */
104static void
105run_finish (void *cls,
106 struct GNUNET_TESTING_Interpreter *is)
107{
108 struct FinishState *finish_state = cls;
109 const struct GNUNET_TESTING_Command *async_cmd;
110 struct GNUNET_TESTING_AsyncContext *aac;
111
112 async_cmd
113 = GNUNET_TESTING_interpreter_lookup_command (is,
114 finish_state->async_label);
115 if (NULL == async_cmd)
116 {
117 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
118 "Did not find command `%s'\n",
119 finish_state->async_label);
120 GNUNET_TESTING_interpreter_fail (is);
121 return;
122 }
123 if ( (NULL == (aac = async_cmd->ac)) ||
124 (! async_cmd->asynchronous_finish) )
125 {
126 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
127 "Cannot finish `%s': not asynchronous\n",
128 finish_state->async_label);
129 GNUNET_TESTING_interpreter_fail (is);
130 return;
131 }
132 if (GNUNET_NO != aac->finished)
133 {
134 /* Command is already finished, so are we! */
135 GNUNET_TESTING_async_finish (&finish_state->ac);
136 return;
137 }
138 finish_state->finish_task
139 = GNUNET_SCHEDULER_add_delayed (finish_state->timeout,
140 &timeout_finish,
141 finish_state);
142 aac->cont = &done_finish;
143 aac->cont_cls = finish_state;
144}
145
146
147/**
148 * Cleanup state of a finish command.
149 *
150 * @param cls a `struct FinishState` to clean up
151 */
152static void
153cleanup_finish (void *cls)
154{
155 struct FinishState *finish_state = cls;
156
157 if (NULL != finish_state->finish_task)
158 {
159 GNUNET_SCHEDULER_cancel (finish_state->finish_task);
160 finish_state->finish_task = NULL;
161 }
162 GNUNET_free (finish_state);
163}
164
165
166const struct GNUNET_TESTING_Command
167GNUNET_TESTING_cmd_finish (const char *finish_label,
168 const char *cmd_ref,
169 struct GNUNET_TIME_Relative timeout)
170{
171 struct FinishState *finish_state;
172
173 finish_state = GNUNET_new (struct FinishState);
174 finish_state->async_label = cmd_ref;
175 finish_state->timeout = timeout;
176 {
177 struct GNUNET_TESTING_Command cmd = {
178 .cls = finish_state,
179 .label = finish_label,
180 .run = &run_finish,
181 .ac = &finish_state->ac,
182 .cleanup = &cleanup_finish
183 };
184
185 return cmd;
186 }
187}
188
189
190struct GNUNET_TESTING_Command
191GNUNET_TESTING_cmd_make_unblocking (struct GNUNET_TESTING_Command cmd)
192{
193 /* do not permit this function to be used on
194 a finish command! */
195 GNUNET_assert (cmd.run != &run_finish);
196 cmd.asynchronous_finish = true;
197 return cmd;
198}