Merge "test_res_pjsip_scheduler: Fix possible write after free in scheduler_policy."
[asterisk/asterisk.git] / tests / test_channel_feature_hooks.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2014, Digium, Inc.
5  *
6  * Kinsey Moore <kmoore@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 /*!
20  * \file
21  * \brief Channel features unit tests
22  *
23  * \author Kinsey Moore <kmoore@digium.com>
24  *
25  */
26
27 /*** MODULEINFO
28         <depend>TEST_FRAMEWORK</depend>
29         <support_level>core</support_level>
30  ***/
31
32 #include "asterisk.h"
33
34 #include "asterisk/module.h"
35 #include "asterisk/test.h"
36 #include "asterisk/channel.h"
37 #include "asterisk/time.h"
38 #include "asterisk/bridge.h"
39 #include "asterisk/bridge_basic.h"
40 #include "asterisk/features.h"
41 #include "asterisk/format_cache.h"
42
43 #define TEST_CATEGORY "/channels/features/"
44
45 #define CHANNEL_TECH_NAME "FeaturesTestChannel"
46
47 #define TEST_BACKEND_NAME "Features Test Logging"
48
49 #define TEST_CHANNEL_FORMAT             ast_format_slin
50
51 /*! \brief A channel technology used for the unit tests */
52 static struct ast_channel_tech test_features_chan_tech = {
53         .type = CHANNEL_TECH_NAME,
54         .description = "Mock channel technology for Features tests",
55 };
56
57 static void test_nanosleep(int secs, long nanosecs)
58 {
59         struct timespec sleep_time = {secs, nanosecs};
60
61         while ((nanosleep(&sleep_time, &sleep_time) == -1) && (errno == EINTR)) {
62         }
63 }
64
65 /*! \brief Wait until a channel is bridged */
66 static void wait_for_bridged(struct ast_channel *channel)
67 {
68         ast_channel_lock(channel);
69         while (!ast_channel_is_bridged(channel)) {
70                 ast_channel_unlock(channel);
71                 test_nanosleep(0, 1000000);
72                 ast_channel_lock(channel);
73         }
74         ast_channel_unlock(channel);
75 }
76
77 /*! \brief Wait until a channel is not bridged */
78 static void wait_for_unbridged(struct ast_channel *channel)
79 {
80         ast_channel_lock(channel);
81         while (ast_channel_is_bridged(channel)) {
82                 ast_channel_unlock(channel);
83                 test_nanosleep(0, 1000000);
84                 ast_channel_lock(channel);
85         }
86         ast_channel_unlock(channel);
87 }
88
89 /*! \brief Create a \ref test_features_chan_tech for Alice. */
90 #define START_ALICE(channel) START_CHANNEL(channel, "Alice", "100")
91
92 /*! \brief Create a \ref test_features_chan_tech for Bob. */
93 #define START_BOB(channel) START_CHANNEL(channel, "Bob", "200")
94
95 #define START_CHANNEL(channel, name, number) do { \
96         channel = ast_channel_alloc(0, AST_STATE_UP, number, name, number, number, \
97                 "default", NULL, NULL, 0, CHANNEL_TECH_NAME "/" name); \
98         ast_channel_nativeformats_set(channel, test_features_chan_tech.capabilities); \
99         ast_channel_set_rawwriteformat(channel, TEST_CHANNEL_FORMAT); \
100         ast_channel_set_rawreadformat(channel, TEST_CHANNEL_FORMAT); \
101         ast_channel_set_writeformat(channel, TEST_CHANNEL_FORMAT); \
102         ast_channel_set_readformat(channel, TEST_CHANNEL_FORMAT); \
103         ast_channel_unlock(channel); \
104         } while (0)
105
106 /*! \brief Hang up a test channel safely */
107 #define HANGUP_CHANNEL(channel) do { \
108         ao2_ref(channel, +1); \
109         ast_hangup((channel)); \
110         ao2_cleanup(channel); \
111         channel = NULL; \
112         } while (0)
113
114 static void safe_channel_release(struct ast_channel *chan)
115 {
116         if (!chan) {
117                 return;
118         }
119         ast_channel_release(chan);
120 }
121
122 static void safe_bridge_destroy(struct ast_bridge *bridge)
123 {
124         if (!bridge) {
125                 return;
126         }
127         ast_bridge_destroy(bridge, 0);
128 }
129
130 static int feature_callback(struct ast_bridge_channel *bridge_channel, void *obj)
131 {
132         int *callback_executed = obj;
133         (*callback_executed)++;
134         return 0;
135 }
136
137 /* Need to post null frames periodically so DTMF emulation can work. */
138 static void stream_periodic_frames(struct ast_channel *chan, int ms, int interval_ms)
139 {
140         long nanosecs;
141
142         ast_assert(chan != NULL);
143         ast_assert(0 < ms);
144         ast_assert(0 < interval_ms);
145
146         nanosecs = interval_ms * 1000000L;
147         while (0 < ms) {
148                 ast_queue_frame(chan, &ast_null_frame);
149
150                 if (interval_ms < ms) {
151                         ms -= interval_ms;
152                 } else {
153                         nanosecs = ms * 1000000L;
154                         ms = 0;
155                 }
156                 test_nanosleep(0, nanosecs);
157         }
158 }
159
160 AST_TEST_DEFINE(test_features_channel_dtmf)
161 {
162         RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
163         RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
164         RAII_VAR(struct ast_bridge *, bridge1, NULL, safe_bridge_destroy);
165         RAII_VAR(struct ast_bridge *, bridge2, NULL, safe_bridge_destroy);
166         struct ast_bridge_features features;
167         int callback_executed = 0;
168         struct ast_frame f = { AST_FRAME_DTMF, };
169
170         switch (cmd) {
171         case TEST_INIT:
172                 info->name = __func__;
173                 info->category = TEST_CATEGORY;
174                 info->summary = "Test running DTMF hooks on a channel via the feature hooks mechanism";
175                 info->description =
176                         "This test creates two channels, adds a DTMF hook to one, places them into\n"
177                         "a bridge, and verifies that the DTMF hook added to the channel feature\n"
178                         "hooks can be triggered once the channel is bridged.";
179                 return AST_TEST_NOT_RUN;
180         case TEST_EXECUTE:
181                 break;
182         }
183
184         /* Create the bridges */
185         bridge1 = ast_bridge_basic_new();
186         ast_test_validate(test, bridge1 != NULL);
187         bridge2 = ast_bridge_basic_new();
188         ast_test_validate(test, bridge2 != NULL);
189
190         /* Create channels that will go into the bridge */
191         START_ALICE(chan_alice);
192         START_BOB(chan_bob);
193
194         /* Setup the features and add them to alice */
195         ast_bridge_features_init(&features);
196         ast_test_validate(test, !ast_bridge_dtmf_hook(&features, "##**", feature_callback, &callback_executed, NULL, 0));
197         ast_test_validate(test, !ast_channel_feature_hooks_append(chan_alice, &features));
198         ast_bridge_features_cleanup(&features);
199
200         /* Bridge the channels */
201         ast_test_validate(test, !ast_bridge_impart(bridge1, chan_alice, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
202         ast_test_validate(test, !ast_bridge_impart(bridge1, chan_bob, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
203
204         wait_for_bridged(chan_alice);
205
206         /* Execute the feature */
207         f.len = 100;
208         f.subclass.integer = '#';
209         ast_queue_frame(chan_alice, &f);
210         ast_queue_frame(chan_alice, &f);
211         f.subclass.integer = '*';
212         ast_queue_frame(chan_alice, &f);
213         ast_queue_frame(chan_alice, &f);
214
215         stream_periodic_frames(chan_alice, 1000, 20);
216
217         /* Remove the channels from the bridge */
218         ast_test_validate(test, !ast_bridge_depart(chan_alice));
219         ast_test_validate(test, !ast_bridge_depart(chan_bob));
220
221         wait_for_unbridged(chan_alice);
222
223         /* Bridge the channels again to ensure that the feature hook remains on the channel */
224         ast_test_validate(test, !ast_bridge_impart(bridge2, chan_alice, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
225         ast_test_validate(test, !ast_bridge_impart(bridge2, chan_bob, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
226
227         wait_for_bridged(chan_alice);
228
229         /* Execute the feature */
230         f.len = 100;
231         f.subclass.integer = '#';
232         ast_queue_frame(chan_alice, &f);
233         ast_queue_frame(chan_alice, &f);
234         f.subclass.integer = '*';
235         ast_queue_frame(chan_alice, &f);
236         ast_queue_frame(chan_alice, &f);
237
238         stream_periodic_frames(chan_alice, 1000, 20);
239
240         /* Remove the channels from the bridge */
241         ast_test_validate(test, !ast_bridge_depart(chan_alice));
242         ast_test_validate(test, !ast_bridge_depart(chan_bob));
243
244         /* Hangup the channels */
245         HANGUP_CHANNEL(chan_alice);
246         HANGUP_CHANNEL(chan_bob);
247
248         ast_test_validate(test, callback_executed == 2);
249
250         return AST_TEST_PASS;
251 }
252
253 AST_TEST_DEFINE(test_features_channel_interval)
254 {
255         RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
256         RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
257         RAII_VAR(struct ast_bridge *, bridge1, NULL, safe_bridge_destroy);
258         RAII_VAR(struct ast_bridge *, bridge2, NULL, safe_bridge_destroy);
259         struct ast_bridge_features features;
260         int callback_executed = 0;
261
262         switch (cmd) {
263         case TEST_INIT:
264                 info->name = __func__;
265                 info->category = TEST_CATEGORY;
266                 info->summary = "Test running interval hooks on a channel via the feature hooks mechanism";
267                 info->description =
268                         "This test creates two channels, adds an interval hook to one, places them\n"
269                         "into a bridge, and verifies that the interval hook added to the channel\n"
270                         "feature hooks is triggered once the channel is bridged.";
271                 return AST_TEST_NOT_RUN;
272         case TEST_EXECUTE:
273                 break;
274         }
275
276         /* Create the bridges */
277         bridge1 = ast_bridge_basic_new();
278         ast_test_validate(test, bridge1 != NULL);
279         bridge2 = ast_bridge_basic_new();
280         ast_test_validate(test, bridge2 != NULL);
281
282         /* Create channels that will go into the bridge */
283         START_ALICE(chan_alice);
284         START_BOB(chan_bob);
285
286         /* Setup the features and add them to alice */
287         ast_bridge_features_init(&features);
288         ast_test_validate(test, !ast_bridge_interval_hook(&features, 0, 1000, feature_callback, &callback_executed, NULL, 0));
289         ast_test_validate(test, !ast_channel_feature_hooks_append(chan_alice, &features));
290         ast_bridge_features_cleanup(&features);
291
292         /* Bridge the channels */
293         ast_test_validate(test, !ast_bridge_impart(bridge1, chan_alice, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
294         ast_test_validate(test, !ast_bridge_impart(bridge1, chan_bob, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
295
296         wait_for_bridged(chan_alice);
297
298         /* Let the interval hook execute once */
299         test_nanosleep(1, 500000000);
300
301         /* Remove the channels from the bridge */
302         ast_test_validate(test, !ast_bridge_depart(chan_alice));
303         ast_test_validate(test, !ast_bridge_depart(chan_bob));
304
305         wait_for_unbridged(chan_alice);
306
307         ast_test_validate(test, callback_executed >= 1);
308         callback_executed = 0;
309
310         /* Bridge the channels again to ensure that the feature hook remains on the channel */
311         ast_test_validate(test, !ast_bridge_impart(bridge2, chan_alice, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
312         ast_test_validate(test, !ast_bridge_impart(bridge2, chan_bob, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
313
314         wait_for_bridged(chan_alice);
315
316         /* Let the interval hook execute once */
317         test_nanosleep(1, 500000000);
318
319         /* Remove the channels from the bridge */
320         ast_test_validate(test, !ast_bridge_depart(chan_alice));
321         ast_test_validate(test, !ast_bridge_depart(chan_bob));
322
323         /* Hangup the channels */
324         HANGUP_CHANNEL(chan_alice);
325         HANGUP_CHANNEL(chan_bob);
326
327         ast_test_validate(test, callback_executed >= 1);
328
329         return AST_TEST_PASS;
330 }
331
332 static int unload_module(void)
333 {
334         AST_TEST_UNREGISTER(test_features_channel_dtmf);
335         AST_TEST_UNREGISTER(test_features_channel_interval);
336
337         ast_channel_unregister(&test_features_chan_tech);
338         ao2_cleanup(test_features_chan_tech.capabilities);
339         test_features_chan_tech.capabilities = NULL;
340
341         return 0;
342 }
343
344 static int load_module(void)
345 {
346         test_features_chan_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
347         if (!test_features_chan_tech.capabilities) {
348                 return AST_MODULE_LOAD_DECLINE;
349         }
350         ast_format_cap_append(test_features_chan_tech.capabilities, TEST_CHANNEL_FORMAT, 0);
351         ast_channel_register(&test_features_chan_tech);
352
353         AST_TEST_REGISTER(test_features_channel_dtmf);
354         AST_TEST_REGISTER(test_features_channel_interval);
355         return AST_MODULE_LOAD_SUCCESS;
356 }
357
358 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Bridge Features Unit Tests");