Asterisk - The Open Source Telephony Project GIT-master-2de1a68
test_bridging.c
Go to the documentation of this file.
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"
40#include "asterisk/features.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 */
51 /*! \brief The expected indication */
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 */
58static 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 */
70static 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);
76
77 return 0;
78}
79
80/*! \brief A channel technology used for the unit tests */
83 .description = "Mock channel technology for bridge tests",
86 .properties = AST_CHAN_TP_INTERNAL,
87};
88
89static 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 */
98static 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 */
110static 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 */
122static 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
160static void safe_channel_release(struct ast_channel *chan)
161{
162 if (!chan) {
163 return;
164 }
166}
167
168static void safe_bridge_destroy(struct ast_bridge *bridge)
169{
170 if (!bridge) {
171 return;
172 }
173 ast_bridge_destroy(bridge, 0);
174}
175
176static 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) {
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
198AST_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 = {
204 };
205 struct ast_frame frame = {
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);
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
265static int unload_module(void)
266{
267 AST_TEST_UNREGISTER(test_bridging_deferred_queue);
268
272
273 return 0;
274}
275
276static int load_module(void)
277{
281 }
284
285 AST_TEST_REGISTER(test_bridging_deferred_queue);
286
288}
289
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
Bridging API.
int ast_bridge_depart(struct ast_channel *chan)
Depart a channel from a bridge.
Definition: bridge.c:1906
int ast_bridge_destroy(struct ast_bridge *bridge, int cause)
Destroy a bridge.
Definition: bridge.c:944
int ast_bridge_impart(struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap, struct ast_bridge_features *features, enum ast_bridge_impart_flags flags) attribute_warn_unused_result
Impart a channel to a bridge (non-blocking)
Definition: bridge.c:1878
@ AST_BRIDGE_IMPART_CHAN_DEPARTABLE
Definition: bridge.h:588
Basic bridge subclass API.
struct ast_bridge * ast_bridge_basic_new(void)
Create a new basic class bridge.
General Asterisk PBX channel definitions.
@ AST_CHAN_TP_INTERNAL
Channels with this particular technology are an implementation detail of Asterisk and should generall...
Definition: channel.h:971
void * ast_channel_tech_pvt(const struct ast_channel *chan)
#define ast_channel_lock(chan)
Definition: channel.h:2922
void ast_channel_unregister(const struct ast_channel_tech *tech)
Unregister a channel technology.
Definition: channel.c:570
int ast_queue_frame(struct ast_channel *chan, struct ast_frame *f)
Queue one or more frames to a channel's frame queue.
Definition: channel.c:1139
void ast_channel_tech_pvt_set(struct ast_channel *chan, void *value)
int ast_channel_is_bridged(const struct ast_channel *chan)
Determine if a channel is in a bridge.
Definition: channel.c:10544
struct ast_channel * ast_channel_release(struct ast_channel *chan)
Unlink and release reference to a channel.
Definition: channel.c:1584
struct ast_readq_list * ast_channel_readq(struct ast_channel *chan)
int ast_channel_register(const struct ast_channel_tech *tech)
Register a channel technology (a new channel driver) Called by a channel module to register the kind ...
Definition: channel.c:539
#define ast_channel_unlock(chan)
Definition: channel.h:2923
Call Parking and Pickup API Includes code and algorithms from the Zapata library.
Media Format Cache API.
@ AST_FORMAT_CAP_FLAG_DEFAULT
Definition: format_cap.h:38
#define ast_format_cap_append(cap, format, framing)
Add format capability to capabilities structure.
Definition: format_cap.h:99
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition: format_cap.h:49
@ AST_T38_REQUEST_NEGOTIATE
@ AST_FRAME_CONTROL
@ AST_CONTROL_T38_PARAMETERS
struct ast_frame ast_null_frame
Definition: main/frame.c:79
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:450
int errno
Asterisk module definitions.
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:567
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
def info(msg)
#define NULL
Definition: resample.c:96
Structure that contains information about a bridge.
Definition: bridge.h:349
Structure to describe a channel "technology", ie a channel driver See for examples:
Definition: channel.h:628
struct ast_format_cap * capabilities
Definition: channel.h:632
const char *const type
Definition: channel.h:629
Main Channel structure associated with a channel.
enum ast_control_t38 request_response
Data structure associated with a single frame of data.
enum ast_frame_type frametype
A private structure for the test channel.
Definition: test_bridging.c:50
int condition
The expected indication.
Definition: test_bridging.c:52
unsigned int indicated
The number of indicated things.
Definition: test_bridging.c:54
Test Framework API.
@ TEST_INIT
Definition: test.h:200
@ TEST_EXECUTE
Definition: test.h:201
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
@ AST_TEST_PASS
Definition: test.h:195
@ AST_TEST_NOT_RUN
Definition: test.h:194
#define TEST_CHANNEL_FORMAT
Definition: test_bridging.c:47
static void wait_for_empty_queue(struct ast_channel *channel)
Wait until a channel has no frames on its read queue.
static int test_bridging_chan_hangup(struct ast_channel *chan)
Callback function for when a channel is hung up.
Definition: test_bridging.c:70
static void safe_bridge_destroy(struct ast_bridge *bridge)
#define CHANNEL_TECH_NAME
Definition: test_bridging.c:45
static int test_bridging_chan_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen)
Callback function for when a frame is written to a channel.
Definition: test_bridging.c:58
#define START_ALICE(channel, pvt)
Create a test_bridging_chan_tech for Alice.
static void safe_channel_release(struct ast_channel *chan)
static void wait_for_unbridged(struct ast_channel *channel)
Wait until a channel is not bridged.
static void test_nanosleep(int secs, long nanosecs)
Definition: test_bridging.c:89
static int load_module(void)
#define START_BOB(channel, pvt)
Create a test_bridging_chan_tech for Bob.
static int unload_module(void)
#define TEST_CATEGORY
Definition: test_bridging.c:43
static void wait_for_bridged(struct ast_channel *channel)
Wait until a channel is bridged.
Definition: test_bridging.c:98
static struct ast_channel_tech test_bridging_chan_tech
A channel technology used for the unit tests.
Definition: test_bridging.c:81
AST_TEST_DEFINE(test_bridging_deferred_queue)
#define HANGUP_CHANNEL(channel)
Hang up a test channel safely.
static void stream_periodic_frames(struct ast_channel *chan, int ms, int interval_ms)
Time-related functions and macros.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
#define ast_assert(a)
Definition: utils.h:739