Merge "doc/lang/language-criteria.txt: Link to wiki."
[asterisk/asterisk.git] / tests / test_amihooks.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2009, Digium, Inc.
5  *
6  * David Brooks <dbrooks@digium.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 /*! \file
20  *
21  * \brief Test AMI hook
22  *
23  * \author David Brooks <dbrooks@digium.com> based off of code written by Russell Bryant <russell@digium.com>
24  *
25  * This started, and continues to serves, as an example illustrating the ability
26  * for a custom module to hook into AMI. Registration for AMI events and sending
27  * of AMI actions is shown. A test has also been created that utilizes the original
28  * example in order to make sure the ami event hook gets raised.
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/module.h"
39 #include "asterisk/cli.h"
40 #include "asterisk/utils.h"
41 #include "asterisk/manager.h"
42 #include "asterisk/test.h"
43
44 #define CATEGORY "/main/amihooks/"
45
46 AST_MUTEX_DEFINE_STATIC(hook_lock);
47 ast_cond_t hook_cond;
48 int done;
49
50 static int wait_for_hook(struct ast_test *test)
51 {
52         struct timeval start = ast_tvnow();
53         struct timespec timeout = {
54                 .tv_sec = start.tv_sec + 2,
55                 .tv_nsec = start.tv_usec * 1000
56         };
57         int res = 0;
58
59         ast_mutex_lock(&hook_lock);
60         while (!done) {
61                 if (ast_cond_timedwait(&hook_cond, &hook_lock, &timeout) == ETIMEDOUT) {
62                         ast_test_status_update(test, "Test timed out while waiting for hook event\n");
63                         res = -1;
64                         break;
65                 }
66         }
67         ast_mutex_unlock(&hook_lock);
68
69         return res;
70 }
71
72 AST_TEST_DEFINE(amihook_cli_send)
73 {
74         switch (cmd) {
75         case TEST_INIT:
76                 info->name = __func__;
77                 info->category = CATEGORY;
78                 info->summary = "Execute an action using an AMI hook";
79                 info->description = info->summary;
80                 return AST_TEST_NOT_RUN;
81         case TEST_EXECUTE:
82                 break;
83         }
84
85         done = 0;
86         if (ast_cli_command(-1, "amihook send")) {
87                 return AST_TEST_FAIL;
88         }
89
90         return wait_for_hook(test) ? AST_TEST_FAIL : AST_TEST_PASS;
91 }
92
93 /* The helper function is required by struct manager_custom_hook. See __manager_event for details */
94 static int amihook_helper(int category, const char *event, char *content)
95 {
96         ast_log(LOG_NOTICE, "AMI Event: \nCategory: %d Event: %s\n%s\n", category, event, content);
97
98         ast_mutex_lock(&hook_lock);
99         done = 1;
100         ast_cond_signal(&hook_cond);
101         ast_mutex_unlock(&hook_lock);
102         return 0;
103 }
104
105 static struct manager_custom_hook test_hook = {
106         .file = __FILE__,
107         .helper = &amihook_helper,
108 };
109
110 static int hook_send(void) {
111         int res;
112
113         /* Send a test action (core show version) to the AMI */
114         res = ast_hook_send_action(&test_hook, "Action: Command\nCommand: core show version\nActionID: 987654321\n");
115
116         return res;
117 }
118
119 static void register_hook(void) {
120
121         /* Unregister the hook, we don't want a double-registration (Bad Things(tm) happen) */
122         ast_manager_unregister_hook(&test_hook);
123
124         /* Register the hook for AMI events */
125         ast_manager_register_hook(&test_hook);
126
127 }
128
129 static void unregister_hook(void) {
130
131         /* Unregister the hook */
132         ast_manager_unregister_hook(&test_hook);
133
134 }
135
136 static char *handle_cli_amihook_send(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
137 {
138         switch (cmd) {
139         case CLI_INIT:
140                 e->command = "amihook send";
141                 e->usage = ""
142                         "Usage: amihook send"
143                         "";
144                 return NULL;
145         case CLI_GENERATE:
146                 return NULL;
147         case CLI_HANDLER:
148                 hook_send();
149                 return CLI_SUCCESS;
150         }
151
152         return CLI_FAILURE;
153 }
154
155 static char *handle_cli_amihook_register_hook(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
156 {
157         switch (cmd) {
158         case CLI_INIT:
159                 e->command = "amihook register";
160                 e->usage = ""
161                         "Usage: amihook register"
162                         "";
163                 return NULL;
164         case CLI_GENERATE:
165                 return NULL;
166         case CLI_HANDLER:
167                 register_hook();
168                 return CLI_SUCCESS;
169         }
170
171         return CLI_FAILURE;
172 }
173
174 static char *handle_cli_amihook_unregister_hook(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
175 {
176         switch (cmd) {
177         case CLI_INIT:
178                 e->command = "amihook unregister";
179                 e->usage = ""
180                         "Usage: amihook unregister"
181                         "";
182                 return NULL;
183         case CLI_GENERATE:
184                 return NULL;
185         case CLI_HANDLER:
186                 unregister_hook();
187                 return CLI_SUCCESS;
188         }
189
190         return CLI_FAILURE;
191 }
192
193 static struct ast_cli_entry cli_amihook_evt[] = {
194         AST_CLI_DEFINE(handle_cli_amihook_send, "Send an AMI event"),
195         AST_CLI_DEFINE(handle_cli_amihook_register_hook, "Register module for AMI hook"),
196         AST_CLI_DEFINE(handle_cli_amihook_unregister_hook, "Unregister module for AMI hook"),
197 };
198
199 static int unload_module(void)
200 {
201         AST_TEST_UNREGISTER(amihook_cli_send);
202         ast_manager_unregister_hook(&test_hook);
203         return ast_cli_unregister_multiple(cli_amihook_evt, ARRAY_LEN(cli_amihook_evt));
204 }
205
206 static int load_module(void)
207 {
208         int res;
209
210         res = ast_cli_register_multiple(cli_amihook_evt, ARRAY_LEN(cli_amihook_evt));
211
212         AST_TEST_REGISTER(amihook_cli_send);
213
214         return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
215 }
216
217 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "AMI Hook Test Module");