Asterisk - The Open Source Telephony Project GIT-master-7e7a603
test_capture.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2022, Philip Prindeville
5 *
6 * Philip Prindeville <philipp@redfish-solutions.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*!
20 * \file
21 * \brief Make basic use of capture capability in test framework.
22 *
23 * \author\verbatim Philip Prindeville <philipp@redfish-solutions.com> \endverbatim
24 *
25 * Exercise the capture capabilities built into the test framework so
26 * that external commands might be used to generate validating results
27 * used on corroborating tests.
28 * \ingroup tests
29 */
30
31/*** MODULEINFO
32 <depend>TEST_FRAMEWORK</depend>
33 <support_level>core</support_level>
34 ***/
35
36#include "asterisk.h"
37
38#include "asterisk/utils.h"
39#include "asterisk/module.h"
40#include "asterisk/test.h"
41
42AST_TEST_DEFINE(test_capture_true)
43{
45 struct ast_test_capture cap;
46 const char *command = "true";
47 char *const args[] = { "true", NULL };
48
49 switch (cmd) {
50 case TEST_INIT:
51 info->name = "test_capture_true";
52 info->category = "/main/test_capture/";
53 info->summary = "capture true exit unit test";
54 info->description =
55 "Capture exit code from true command.";
56 return AST_TEST_NOT_RUN;
57 case TEST_EXECUTE:
58 break;
59 }
60
61 ast_test_status_update(test, "Executing true exit test...\n");
62
63 if (!ast_check_command_in_path(command)) {
64 ast_test_status_update(test, "couldn't find %s\n", command);
65 return status;
66 }
67
68 if (ast_test_capture_command(&cap, command, args, NULL, 0) != 1) {
69 ast_test_status_update(test, "ast_test_capture_command() failed\n");
70 return status;
71 }
72
73 if (cap.outlen != 0) {
74 ast_test_status_update(test, "unexpected value for stdout\n");
75 goto cleanup;
76 }
77
78 if (cap.errlen != 0) {
79 ast_test_status_update(test, "unexpected value for stderr\n");
80 goto cleanup;
81 }
82
83 if (cap.pid == -1) {
84 ast_test_status_update(test, "invalid process id\n");
85 goto cleanup;
86 }
87
88 if (cap.exitcode != 0) {
89 ast_test_status_update(test, "child exited %d\n", cap.exitcode);
90 goto cleanup;
91 }
92
94
96 ast_test_capture_free(&cap);
97
98 return status;
99}
100
101AST_TEST_DEFINE(test_capture_false)
102{
103 int status = AST_TEST_FAIL;
104 struct ast_test_capture cap;
105 const char *command = "false";
106 char *const args[] = { "false", NULL };
107
108 switch (cmd) {
109 case TEST_INIT:
110 info->name = "test_capture_false";
111 info->category = "/main/test_capture/";
112 info->summary = "capture false exit unit test";
113 info->description =
114 "Capture exit code from false command.";
115 return AST_TEST_NOT_RUN;
116 case TEST_EXECUTE:
117 break;
118 }
119
120 ast_test_status_update(test, "Executing false exit test...\n");
121
122 if (!ast_check_command_in_path(command)) {
123 ast_test_status_update(test, "couldn't find %s\n", command);
124 return status;
125 }
126
127 if (ast_test_capture_command(&cap, command, args, NULL, 0) != 1) {
128 ast_test_status_update(test, "ast_test_capture_command() failed\n");
129 return status;
130 }
131
132 if (cap.outlen != 0) {
133 ast_test_status_update(test, "unexpected value for stdout\n");
134 goto cleanup;
135 }
136
137 if (cap.errlen != 0) {
138 ast_test_status_update(test, "unexpected value for stderr\n");
139 goto cleanup;
140 }
141
142 if (cap.pid == -1) {
143 ast_test_status_update(test, "invalid process id\n");
144 goto cleanup;
145 }
146
147 if (cap.exitcode != 1) {
148 ast_test_status_update(test, "child exited %d\n", cap.exitcode);
149 goto cleanup;
150 }
151
153
154cleanup:
155 ast_test_capture_free(&cap);
156
157 return status;
158}
159
160AST_TEST_DEFINE(test_capture_with_stdin)
161{
162 int status = AST_TEST_FAIL;
163 struct ast_test_capture cap;
164 const char *command = "base64";
165 char *const args[] = { "base64", NULL };
166 const char data[] = "Mary had a little lamb.";
167 const unsigned datalen = sizeof(data) - 1;
168 const char output[] = "TWFyeSBoYWQgYSBsaXR0bGUgbGFtYi4=\n";
169 const unsigned outputlen = sizeof(output) - 1;
170
171 switch (cmd) {
172 case TEST_INIT:
173 info->name = "test_capture_with_stdin";
174 info->category = "/main/test_capture/";
175 info->summary = "capture with stdin unit test";
176 info->description =
177 "Capture output from stdin transformation command.";
178 return AST_TEST_NOT_RUN;
179 case TEST_EXECUTE:
180 break;
181 }
182
183 ast_test_status_update(test, "Executing stdin test...\n");
184
185 if (!ast_check_command_in_path(command)) {
186 ast_test_status_update(test, "couldn't find %s\n", command);
187 return status;
188 }
189
190 if (ast_test_capture_command(&cap, command, args, data, datalen) != 1) {
191 ast_test_status_update(test, "ast_test_capture_command() failed\n");
192 return status;
193 }
194
195 if (cap.outlen != outputlen || memcmp(cap.outbuf, output, cap.outlen)) {
196 ast_test_status_update(test, "unexpected value for stdout\n");
197 goto cleanup;
198 }
199
200 if (cap.errlen != 0) {
201 ast_test_status_update(test, "unexpected value for stderr\n");
202 goto cleanup;
203 }
204
205 if (cap.pid == -1) {
206 ast_test_status_update(test, "invalid process id\n");
207 goto cleanup;
208 }
209
210 if (cap.exitcode != 0) {
211 ast_test_status_update(test, "child exited %d\n", cap.exitcode);
212 goto cleanup;
213 }
214
216
217cleanup:
218 ast_test_capture_free(&cap);
219
220 return status;
221}
222
223AST_TEST_DEFINE(test_capture_with_dynamic)
224{
225 int status = AST_TEST_FAIL;
226 struct ast_test_capture cap;
227 const char *command = "date";
228 char *args[] = { "date", "DATE", "FORMAT", NULL };
229 char date[40];
230 const char format[] = "+%a, %d %b %y %T %z";
231 const char format2[] = "%a, %d %b %y %T %z\n";
232 char myresult[64];
233 unsigned myresultlen;
234 time_t now;
235 struct tm *tm;
236
237 switch (cmd) {
238 case TEST_INIT:
239 info->name = "test_capture_with_dynamic";
240 info->category = "/main/test_capture/";
241 info->summary = "capture with dynamic argument unit test";
242 info->description =
243 "Capture output from dynamic transformation command.";
244 return AST_TEST_NOT_RUN;
245 case TEST_EXECUTE:
246 break;
247 }
248
249 ast_test_status_update(test, "Executing dynamic argument test...\n");
250
251 if (!ast_check_command_in_path(command)) {
252 ast_test_status_update(test, "couldn't find %s\n", command);
253 return status;
254 }
255
256 time(&now);
257 snprintf(date, sizeof(date), "--date=@%lu", now);
258
259 tm = localtime(&now);
260 strftime(myresult, sizeof(myresult), format2, tm);
261 myresultlen = strlen(myresult);
262
263 args[1] = date;
264 args[2] = (char *)format;
265
266 if (ast_test_capture_command(&cap, command, args, NULL, 0) != 1) {
267 ast_test_status_update(test, "ast_test_capture_command() failed\n");
268 return status;
269 }
270
271 if (cap.outlen != myresultlen || memcmp(cap.outbuf, myresult, cap.outlen)) {
272 ast_test_status_update(test, "unexpected value for stdout\n");
273 goto cleanup;
274 }
275
276 if (cap.errlen != 0) {
277 ast_test_status_update(test, "unexpected value for stderr\n");
278 goto cleanup;
279 }
280
281 if (cap.pid == -1) {
282 ast_test_status_update(test, "invalid process id\n");
283 goto cleanup;
284 }
285
286 if (cap.exitcode != 0) {
287 ast_test_status_update(test, "child exited %d\n", cap.exitcode);
288 goto cleanup;
289 }
290
292
293cleanup:
294 ast_test_capture_free(&cap);
295
296 return status;
297}
298
299AST_TEST_DEFINE(test_capture_stdout_stderr)
300{
301 int status = AST_TEST_FAIL;
302 struct ast_test_capture cap;
303 const char *command = "sh";
304 char *const args[] = { "sh", "-c", "echo -n 'foo' >&2 ; echo -n 'zzz' >&1 ; echo -n 'bar' >&2", NULL };
305
306 switch (cmd) {
307 case TEST_INIT:
308 info->name = "test_capture_stdout_stderr";
309 info->category = "/main/test_capture/";
310 info->summary = "capture stdout & stderr unit test";
311 info->description =
312 "Capture both stdout and stderr from shell.";
313 return AST_TEST_NOT_RUN;
314 case TEST_EXECUTE:
315 break;
316 }
317
318 ast_test_status_update(test, "Executing stdout/stderr test...\n");
319
320 if (!ast_check_command_in_path(command)) {
321 ast_test_status_update(test, "couldn't find %s\n", command);
322 return status;
323 }
324
325 if (ast_test_capture_command(&cap, command, args, NULL, 0) != 1) {
326 ast_test_status_update(test, "ast_test_capture_command() failed\n");
327 return status;
328 }
329
330 if (cap.outlen != 3 || memcmp(cap.outbuf, "zzz", 3)) {
331 ast_test_status_update(test, "unexpected value for stdout\n");
332 goto cleanup;
333 }
334
335 if (cap.errlen != 6 || memcmp(cap.errbuf, "foobar", 6)) {
336 ast_test_status_update(test, "unexpected value for stderr\n");
337 goto cleanup;
338 }
339
340 if (cap.pid == -1) {
341 ast_test_status_update(test, "invalid process id\n");
342 goto cleanup;
343 }
344
345 if (cap.exitcode != 0) {
346 ast_test_status_update(test, "child exited %d\n", cap.exitcode);
347 goto cleanup;
348 }
349
351
352cleanup:
353 ast_test_capture_free(&cap);
354
355 return status;
356}
357
358static int unload_module(void)
359{
360 AST_TEST_UNREGISTER(test_capture_with_stdin);
361 AST_TEST_UNREGISTER(test_capture_with_dynamic);
362 AST_TEST_UNREGISTER(test_capture_stdout_stderr);
363 AST_TEST_UNREGISTER(test_capture_true);
364 AST_TEST_UNREGISTER(test_capture_false);
365 return 0;
366}
367
368static int load_module(void)
369{
370 AST_TEST_REGISTER(test_capture_with_stdin);
371 AST_TEST_REGISTER(test_capture_with_dynamic);
372 AST_TEST_REGISTER(test_capture_stdout_stderr);
373 AST_TEST_REGISTER(test_capture_true);
374 AST_TEST_REGISTER(test_capture_false);
376}
377
379
jack_status_t status
Definition: app_jack.c:146
Asterisk main include file. File version handling, generic pbx functions.
Asterisk module definitions.
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:567
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
def info(msg)
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124
#define NULL
Definition: resample.c:96
A capture of running an external process.
Definition: test.h:217
char * outbuf
buffer holding stdout
Definition: test.h:219
char * errbuf
buffer holding stderr
Definition: test.h:223
size_t errlen
length of buffer holding stderr
Definition: test.h:225
pid_t pid
process id of child
Definition: test.h:227
size_t outlen
length of buffer holding stdout
Definition: test.h:221
int exitcode
exit code of child
Definition: test.h:229
Test Framework API.
@ TEST_INIT
Definition: test.h:200
@ TEST_EXECUTE
Definition: test.h:201
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
@ AST_TEST_PASS
Definition: test.h:195
@ AST_TEST_FAIL
Definition: test.h:196
@ AST_TEST_NOT_RUN
Definition: test.h:194
AST_TEST_DEFINE(test_capture_true)
Definition: test_capture.c:42
static int load_module(void)
Definition: test_capture.c:368
static int unload_module(void)
Definition: test_capture.c:358
const char * args
Utility functions.
int ast_check_command_in_path(const char *cmd)
Test for the presence of an executable command in $PATH.
Definition: utils.c:3263