Skip to content

Commit 401ef62

Browse files
authored
app_assert: add Assert application
Adds Assert application. This is not a new change, just a rehome from the Asterisk Gerrit, since it's not going to be merged there, and this ensures the module remains available once that Gerrit is decomissioned.
1 parent 9acefca commit 401ef62

File tree

1 file changed

+164
-0
lines changed

1 file changed

+164
-0
lines changed

apps/app_assert.c

+164
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
/*
2+
* Asterisk -- An open source telephony toolkit.
3+
*
4+
* Copyright (C) 2021, Naveen Albert
5+
*
6+
* Naveen Albert <[email protected]>
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+
/*! \file
20+
*
21+
* \brief Dialplan assertion application
22+
*
23+
* \author Naveen Albert <[email protected]>
24+
*
25+
* \ingroup applications
26+
*/
27+
28+
/*** MODULEINFO
29+
<support_level>extended</support_level>
30+
***/
31+
32+
#include "asterisk.h"
33+
34+
#include "asterisk/file.h"
35+
#include "asterisk/pbx.h"
36+
#include "asterisk/channel.h"
37+
#include "asterisk/app.h"
38+
#include "asterisk/module.h"
39+
40+
/*** DOCUMENTATION
41+
<application name="Assert" language="en_US">
42+
<synopsis>
43+
Asserts that an expression is true.
44+
</synopsis>
45+
<syntax>
46+
<parameter name="expression">
47+
<para>The expression to evaluate.</para>
48+
</parameter>
49+
<parameter name="options">
50+
<optionlist>
51+
<option name="d">
52+
<para>Do not hang up if expression is false.</para>
53+
</option>
54+
</optionlist>
55+
</parameter>
56+
</syntax>
57+
<description>
58+
<para>Evaluates <replaceable>expression</replaceable> and continues dialplan
59+
execution if the expression is true and ends the call with a warning
60+
if it is false (unless the <replaceable>d</replaceable> option is provided).</para>
61+
<para>This application can be used to verify functional correctness
62+
of dialplans (e.g. dialplan test cases), similar to the <replaceable>assert</replaceable>
63+
function in C. For instance, if a certain property is expected to always hold at some
64+
point in your dialplan, this application can be used to enforce that.</para>
65+
</description>
66+
<see-also>
67+
<ref type="application">RaiseException</ref>
68+
</see-also>
69+
</application>
70+
***/
71+
72+
enum option_flags {
73+
OPT_NOHANGUP = (1 << 0),
74+
};
75+
76+
AST_APP_OPTIONS(app_options, {
77+
AST_APP_OPTION('d', OPT_NOHANGUP),
78+
});
79+
80+
static const char *app = "Assert";
81+
82+
static int assert_exec(struct ast_channel *chan, const char *data)
83+
{
84+
char *argcopy = NULL;
85+
struct ast_flags flags = {0};
86+
int value = 0;
87+
88+
AST_DECLARE_APP_ARGS(arglist,
89+
AST_APP_ARG(expression);
90+
AST_APP_ARG(options);
91+
);
92+
93+
if (ast_strlen_zero(data)) {
94+
ast_log(LOG_WARNING, "%s requires an argument (variable)\n", app);
95+
return -1;
96+
}
97+
98+
argcopy = ast_strdupa(data);
99+
100+
AST_STANDARD_APP_ARGS(arglist, argcopy);
101+
102+
if (!ast_strlen_zero(arglist.options)) {
103+
ast_app_parse_options(app_options, &flags, NULL, arglist.options);
104+
}
105+
106+
if (ast_strlen_zero(arglist.expression)) {
107+
ast_log(LOG_WARNING, "%s requires an argument (variable)\n", app);
108+
return -1;
109+
}
110+
111+
value = atoi(arglist.expression); /* already parsed, so it should already be an integer anyways */
112+
113+
if (!value) {
114+
AST_DECLARE_APP_ARGS(extendata,
115+
AST_APP_ARG(expr);
116+
AST_APP_ARG(rest);
117+
);
118+
const char *exprparse = NULL;
119+
char *datacopy = NULL;
120+
char *context, *exten;
121+
int priority;
122+
123+
/* so, what was the expression? Let's find out */
124+
struct ast_exten *e;
125+
struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
126+
127+
ast_channel_lock(chan);
128+
context = ast_strdupa(ast_channel_context(chan));
129+
exten = ast_strdupa(ast_channel_exten(chan));
130+
priority = ast_channel_priority(chan);
131+
ast_channel_unlock(chan);
132+
133+
ast_rdlock_contexts();
134+
e = pbx_find_extension(chan, NULL, &q, context, exten, priority, NULL, "", E_MATCH);
135+
ast_unlock_contexts();
136+
if (!e) {
137+
ast_log(LOG_WARNING, "Couldn't find current execution location\n"); /* should never happen */
138+
return -1;
139+
}
140+
exprparse = ast_get_extension_app_data(e);
141+
datacopy = ast_strdupa(exprparse);
142+
AST_STANDARD_APP_ARGS(extendata, datacopy);
143+
144+
ast_log(LOG_WARNING, "Assertion failed at %s,%s,%d: %s\n", context, exten, priority, extendata.expr);
145+
146+
if (!ast_test_flag(&flags, OPT_NOHANGUP)) {
147+
return -1;
148+
}
149+
}
150+
151+
return 0;
152+
}
153+
154+
static int unload_module(void)
155+
{
156+
return ast_unregister_application(app);
157+
}
158+
159+
static int load_module(void)
160+
{
161+
return ast_register_application_xml(app, assert_exec);
162+
}
163+
164+
AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "Dialplan assertion test application");

0 commit comments

Comments
 (0)