Merge "Revert "app_voicemail: Remove need to subscribe to stasis""
[asterisk/asterisk.git] / tests / test_bridging.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2017, Digium, Inc.
5  *
6  * Joshua Colp <jcolp@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 Bridging unit tests
22  *
23  * \author Joshua Colp <jcolp@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 "/main/bridging/"
44
45 #define CHANNEL_TECH_NAME "BridgingTestChannel"
46
47 #define TEST_CHANNEL_FORMAT             ast_format_slin
48
49 /*! \brief A private structure for the test channel */
50 struct test_bridging_chan_pvt {
51         /* \brief The expected indication */
52         int condition;
53         /*! \brief The number of indicated things */
54         unsigned int indicated;
55 };
56
57 /*! \brief Callback function for when a frame is written to a channel */
58 static int test_bridging_chan_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen)
59 {
60         struct test_bridging_chan_pvt *test_pvt = ast_channel_tech_pvt(chan);
61
62         if (condition == test_pvt->condition) {
63                 test_pvt->indicated++;
64         }
65
66         return 0;
67 }
68
69 /*! \brief Callback function for when a channel is hung up */
70 static int test_bridging_chan_hangup(struct ast_channel *chan)
71 {
72         struct test_bridging_chan_pvt *test_pvt = ast_channel_tech_pvt(chan);
73
74         ast_free(test_pvt);
75         ast_channel_tech_pvt_set(chan, NULL);
76
77         return 0;
78 }
79
80 /*! \brief A channel technology used for the unit tests */
81 static struct ast_channel_tech test_bridging_chan_tech = {
82         .type = CHANNEL_TECH_NAME,
83         .description = "Mock channel technology for bridge tests",
84         .indicate = test_bridging_chan_indicate,
85         .hangup = test_bridging_chan_hangup,
86         .properties = AST_CHAN_TP_INTERNAL,
87 };
88
89 static void test_nanosleep(int secs, long nanosecs)
90 {
91         struct timespec sleep_time = {secs, nanosecs};
92
93         while ((nanosleep(&sleep_time, &sleep_time) == -1) && (errno == EINTR)) {
94         }
95 }
96
97 /*! \brief Wait until a channel is bridged */
98 static void wait_for_bridged(struct ast_channel *channel)
99 {
100         ast_channel_lock(channel);
101         while (!ast_channel_is_bridged(channel)) {
102                 ast_channel_unlock(channel);
103                 test_nanosleep(0, 1000000);
104                 ast_channel_lock(channel);
105         }
106         ast_channel_unlock(channel);
107 }
108
109 /*! \brief Wait until a channel is not bridged */
110 static void wait_for_unbridged(struct ast_channel *channel)
111 {
112         ast_channel_lock(channel);
113         while (ast_channel_is_bridged(channel)) {
114                 ast_channel_unlock(channel);
115                 test_nanosleep(0, 1000000);
116                 ast_channel_lock(channel);
117         }
118         ast_channel_unlock(channel);
119 }
120
121 /*! \brief Wait until a channel has no frames on its read queue */
122 static void wait_for_empty_queue(struct ast_channel *channel)
123 {
124         ast_channel_lock(channel);
125         while (!AST_LIST_EMPTY(ast_channel_readq(channel))) {
126                 ast_channel_unlock(channel);
127                 test_nanosleep(0, 1000000);
128                 ast_channel_lock(channel);
129         }
130         ast_channel_unlock(channel);
131 }
132
133 /*! \brief Create a \ref test_bridging_chan_tech for Alice. */
134 #define START_ALICE(channel, pvt) START_CHANNEL(channel, pvt, "Alice", "100")
135
136 /*! \brief Create a \ref test_bridging_chan_tech for Bob. */
137 #define START_BOB(channel, pvt) START_CHANNEL(channel, pvt, "Bob", "200")
138
139 #define START_CHANNEL(channel, pvt, name, number) do { \
140         channel = ast_channel_alloc(0, AST_STATE_UP, number, name, number, number, \
141                 "default", NULL, NULL, 0, CHANNEL_TECH_NAME "/" name); \
142         pvt = ast_calloc(1, sizeof(*pvt)); \
143         ast_channel_tech_pvt_set(channel, pvt); \
144         ast_channel_nativeformats_set(channel, test_bridging_chan_tech.capabilities); \
145         ast_channel_set_rawwriteformat(channel, TEST_CHANNEL_FORMAT); \
146         ast_channel_set_rawreadformat(channel, TEST_CHANNEL_FORMAT); \
147         ast_channel_set_writeformat(channel, TEST_CHANNEL_FORMAT); \
148         ast_channel_set_readformat(channel, TEST_CHANNEL_FORMAT); \
149         ast_channel_unlock(channel); \
150         } while (0)
151
152 /*! \brief Hang up a test channel safely */
153 #define HANGUP_CHANNEL(channel) do { \
154         ao2_ref(channel, +1); \
155         ast_hangup((channel)); \
156         ao2_cleanup(channel); \
157         channel = NULL; \
158         } while (0)
159
160 static void safe_channel_release(struct ast_channel *chan)
161 {
162         if (!chan) {
163                 return;
164         }
165         ast_channel_release(chan);
166 }
167
168 static void safe_bridge_destroy(struct ast_bridge *bridge)
169 {
170         if (!bridge) {
171                 return;
172         }
173         ast_bridge_destroy(bridge, 0);
174 }
175
176 static void stream_periodic_frames(struct ast_channel *chan, int ms, int interval_ms)
177 {
178         long nanosecs;
179
180         ast_assert(chan != NULL);
181         ast_assert(0 < ms);
182         ast_assert(0 < interval_ms);
183
184         nanosecs = interval_ms * 1000000L;
185         while (0 < ms) {
186                 ast_queue_frame(chan, &ast_null_frame);
187
188                 if (interval_ms < ms) {
189                         ms -= interval_ms;
190                 } else {
191                         nanosecs = ms * 1000000L;
192                         ms = 0;
193                 }
194                 test_nanosleep(0, nanosecs);
195         }
196 }
197
198 AST_TEST_DEFINE(test_bridging_deferred_queue)
199 {
200         RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
201         struct test_bridging_chan_pvt *alice_pvt;
202                 struct ast_control_t38_parameters t38_parameters = {
203                         .request_response = AST_T38_REQUEST_NEGOTIATE,
204                 };
205                 struct ast_frame frame = {
206                         .frametype = AST_FRAME_CONTROL,
207                         .subclass.integer = AST_CONTROL_T38_PARAMETERS,
208                         .data.ptr = &t38_parameters,
209                         .datalen = sizeof(t38_parameters),
210                 };
211         RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
212         struct test_bridging_chan_pvt *bob_pvt;
213         RAII_VAR(struct ast_bridge *, bridge1, NULL, safe_bridge_destroy);
214
215         switch (cmd) {
216         case TEST_INIT:
217                 info->name = __func__;
218                 info->category = TEST_CATEGORY;
219                 info->summary = "Test that deferred frames from a channel in a bridge get written";
220                 info->description =
221                         "This test creates two channels, queues a deferrable frame on one, places it into\n"
222                         "a bridge, confirms the frame was read by the bridge, adds the second channel to the\n"
223                         "bridge, and makes sure the deferred frame is written to it.";
224                 return AST_TEST_NOT_RUN;
225         case TEST_EXECUTE:
226                 break;
227         }
228
229         /* Create the bridges */
230         bridge1 = ast_bridge_basic_new();
231         ast_test_validate(test, bridge1 != NULL);
232
233         /* Create channels that will go into the bridge */
234         START_ALICE(chan_alice, alice_pvt);
235         START_BOB(chan_bob, bob_pvt);
236         bob_pvt->condition = AST_CONTROL_T38_PARAMETERS;
237
238         /* Bridge alice and wait for the frame to be deferred */
239         ast_test_validate(test, !ast_bridge_impart(bridge1, chan_alice, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
240         wait_for_bridged(chan_alice);
241         ast_queue_frame(chan_alice, &frame);
242         wait_for_empty_queue(chan_alice);
243
244         /* Bridge bob for a second so it can receive the deferred T.38 request negotiate frame */
245         ast_test_validate(test, !ast_bridge_impart(bridge1, chan_bob, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
246         wait_for_bridged(chan_bob);
247         stream_periodic_frames(chan_alice, 1000, 20);
248         ast_test_validate(test, !ast_bridge_depart(chan_bob));
249         wait_for_unbridged(chan_bob);
250
251         /* Ensure that we received the expected indications while it was in there (request to negotiate, and to terminate) */
252         ast_test_validate(test, bob_pvt->indicated == 2);
253
254         /* Now remove alice since we are done */
255         ast_test_validate(test, !ast_bridge_depart(chan_alice));
256         wait_for_unbridged(chan_alice);
257
258         /* Hangup the channels */
259         HANGUP_CHANNEL(chan_alice);
260         HANGUP_CHANNEL(chan_bob);
261
262         return AST_TEST_PASS;
263 }
264
265 static int unload_module(void)
266 {
267         AST_TEST_UNREGISTER(test_bridging_deferred_queue);
268
269         ast_channel_unregister(&test_bridging_chan_tech);
270         ao2_cleanup(test_bridging_chan_tech.capabilities);
271         test_bridging_chan_tech.capabilities = NULL;
272
273         return 0;
274 }
275
276 static int load_module(void)
277 {
278         test_bridging_chan_tech.capabilities = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
279         if (!test_bridging_chan_tech.capabilities) {
280                 return AST_MODULE_LOAD_DECLINE;
281         }
282         ast_format_cap_append(test_bridging_chan_tech.capabilities, TEST_CHANNEL_FORMAT, 0);
283         ast_channel_register(&test_bridging_chan_tech);
284
285         AST_TEST_REGISTER(test_bridging_deferred_queue);
286
287         return AST_MODULE_LOAD_SUCCESS;
288 }
289
290 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Bridging Unit Tests");