Merge "Revert "app_voicemail: Remove need to subscribe to stasis""
[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.
94  * See __ast_manager_event_multichan for details */
95 static int amihook_helper(int category, const char *event, char *content)
96 {
97         ast_log(LOG_NOTICE, "AMI Event: \nCategory: %d Event: %s\n%s\n", category, event, content);
98
99         ast_mutex_lock(&hook_lock);
100         done = 1;
101         ast_cond_signal(&hook_cond);
102         ast_mutex_unlock(&hook_lock);
103         return 0;
104 }
105
106 static struct manager_custom_hook test_hook = {
107         .file = __FILE__,
108         .helper = &amihook_helper,
109 };
110
111 static int hook_send(void) {
112         int res;
113
114         /* Send a test action (core show version) to the AMI */
115         res = ast_hook_send_action(&test_hook, "Action: Command\nCommand: core show version\nActionID: 987654321\n");
116
117         return res;
118 }
119
120 static void register_hook(void) {
121
122         /* Unregister the hook, we don't want a double-registration (Bad Things(tm) happen) */
123         ast_manager_unregister_hook(&test_hook);
124
125         /* Register the hook for AMI events */
126         ast_manager_register_hook(&test_hook);
127
128 }
129
130 static void unregister_hook(void) {
131
132         /* Unregister the hook */
133         ast_manager_unregister_hook(&test_hook);
134
135 }
136
137 static char *handle_cli_amihook_send(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
138 {
139         switch (cmd) {
140         case CLI_INIT:
141                 e->command = "amihook send";
142                 e->usage = ""
143                         "Usage: amihook send"
144                         "";
145                 return NULL;
146         case CLI_GENERATE:
147                 return NULL;
148         case CLI_HANDLER:
149                 hook_send();
150                 return CLI_SUCCESS;
151         }
152
153         return CLI_FAILURE;
154 }
155
156 static char *handle_cli_amihook_register_hook(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
157 {
158         switch (cmd) {
159         case CLI_INIT:
160                 e->command = "amihook register";
161                 e->usage = ""
162                         "Usage: amihook register"
163                         "";
164                 return NULL;
165         case CLI_GENERATE:
166                 return NULL;
167         case CLI_HANDLER:
168                 register_hook();
169                 return CLI_SUCCESS;
170         }
171
172         return CLI_FAILURE;
173 }
174
175 static char *handle_cli_amihook_unregister_hook(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
176 {
177         switch (cmd) {
178         case CLI_INIT:
179                 e->command = "amihook unregister";
180                 e->usage = ""
181                         "Usage: amihook unregister"
182                         "";
183                 return NULL;
184         case CLI_GENERATE:
185                 return NULL;
186         case CLI_HANDLER:
187                 unregister_hook();
188                 return CLI_SUCCESS;
189         }
190
191         return CLI_FAILURE;
192 }
193
194 static struct ast_cli_entry cli_amihook_evt[] = {
195         AST_CLI_DEFINE(handle_cli_amihook_send, "Send an AMI event"),
196         AST_CLI_DEFINE(handle_cli_amihook_register_hook, "Register module for AMI hook"),
197         AST_CLI_DEFINE(handle_cli_amihook_unregister_hook, "Unregister module for AMI hook"),
198 };
199
200 static int unload_module(void)
201 {
202         AST_TEST_UNREGISTER(amihook_cli_send);
203         ast_manager_unregister_hook(&test_hook);
204         return ast_cli_unregister_multiple(cli_amihook_evt, ARRAY_LEN(cli_amihook_evt));
205 }
206
207 static int load_module(void)
208 {
209         int res;
210
211         res = ast_cli_register_multiple(cli_amihook_evt, ARRAY_LEN(cli_amihook_evt));
212
213         AST_TEST_REGISTER(amihook_cli_send);
214
215         return res ? AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
216 }
217
218 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "AMI Hook Test Module");