Asterisk - The Open Source Telephony Project GIT-master-f36a736
test_stasis_channels.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2013, Digium, Inc.
5 *
6 * Matt Jordan <mjordan@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 Test Stasis Channel messages and objects
22 *
23 * \author\verbatim Matt Jordan <mjordan@digium.com> \endverbatim
24 *
25 * \ingroup tests
26 */
27
28/*** MODULEINFO
29 <depend>TEST_FRAMEWORK</depend>
30 <support_level>core</support_level>
31 ***/
32
33#include "asterisk.h"
34
35#include "asterisk/astobj2.h"
36#include "asterisk/module.h"
37#include "asterisk/stasis.h"
39#include "asterisk/test.h"
41#include "asterisk/channel.h"
42
43static const char *test_category = "/stasis/channels/";
44
45static void safe_channel_release(struct ast_channel *chan)
46{
47 if (!chan) {
48 return;
49 }
51}
52
53AST_TEST_DEFINE(channel_blob_create)
54{
55 struct ast_channel_blob *blob;
57 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
59 RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
60 RAII_VAR(struct ast_json *, bad_json, NULL, ast_json_unref);
61
62 switch (cmd) {
63 case TEST_INIT:
64 info->name = __func__;
65 info->category = test_category;
66 info->summary = "Test creation of ast_channel_blob objects";
67 info->description = "Test creation of ast_channel_blob objects";
68 return AST_TEST_NOT_RUN;
69 case TEST_EXECUTE:
70 break;
71 }
72
73 ast_test_validate(test, stasis_message_type_create("test-type", NULL, &type) == STASIS_MESSAGE_TYPE_SUCCESS);
74 chan = ast_channel_alloc(0, AST_STATE_DOWN, "100", "Alice", "100", "100", "default", NULL, NULL, 0, "TEST/Alice");
76 json = ast_json_pack("{s: s}",
77 "foo", "bar");
78
79 /* Off nominal creation */
80 ast_channel_lock(chan);
81 ast_test_validate(test, NULL == ast_channel_blob_create(chan, NULL, json));
82
83 /* Test for single channel */
84 msg = ast_channel_blob_create(chan, type, json);
86 ast_test_validate(test, NULL != msg);
88 ast_test_validate(test, NULL != blob);
89 ast_test_validate(test, NULL != blob->snapshot);
90 ast_test_validate(test, NULL != blob->blob);
91 ast_test_validate(test, type == stasis_message_type(msg));
92
93 ast_test_validate(test, 1 == ao2_ref(msg, 0));
94 ao2_cleanup(msg);
95
96 /* Test for global channels */
97 msg = ast_channel_blob_create(NULL, type, json);
98 ast_test_validate(test, NULL != msg);
100 ast_test_validate(test, NULL != blob);
101 ast_test_validate(test, NULL == blob->snapshot);
102 ast_test_validate(test, NULL != blob->blob);
103 ast_test_validate(test, type == stasis_message_type(msg));
104
105 return AST_TEST_PASS;
106}
107
109{
110 struct ast_channel_blob *blob;
112 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
114 RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
115 RAII_VAR(struct ast_json *, bad_json, NULL, ast_json_unref);
116
117 switch (cmd) {
118 case TEST_INIT:
119 info->name = __func__;
120 info->category = test_category;
121 info->summary = "Test creation of ast_channel_blob objects";
122 info->description = "Test creation of ast_channel_blob objects";
123 return AST_TEST_NOT_RUN;
124 case TEST_EXECUTE:
125 break;
126 }
127
128 ast_test_validate(test, stasis_message_type_create("test-type", NULL, &type) == STASIS_MESSAGE_TYPE_SUCCESS);
129 chan = ast_channel_alloc(0, AST_STATE_DOWN, "100", "Alice", "100", "100", "default", NULL, NULL, 0, "TEST/Alice");
130 ast_channel_unlock(chan);
131 json = ast_json_pack("{s: s}",
132 "foo", "bar");
133
134 /* Test for single channel */
135 ast_channel_lock(chan);
136 msg = ast_channel_blob_create(chan, type, NULL);
137 ast_channel_unlock(chan);
138 ast_test_validate(test, NULL != msg);
140 ast_test_validate(test, NULL != blob);
141 ast_test_validate(test, NULL != blob->snapshot);
142 ast_test_validate(test, ast_json_null() == blob->blob);
143 ast_test_validate(test, type == stasis_message_type(msg));
144
145 return AST_TEST_PASS;
146}
147
148AST_TEST_DEFINE(multi_channel_blob_create)
149{
151 RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
152 RAII_VAR(struct ast_json *, bad_json, NULL, ast_json_unref);
153
154 switch (cmd) {
155 case TEST_INIT:
156 info->name = __func__;
157 info->category = test_category;
158 info->summary = "Test creation of ast_multi_channel_blob objects";
159 info->description = "Test creation of ast_multi_channel_blob objects";
160 return AST_TEST_NOT_RUN;
161 case TEST_EXECUTE:
162 break;
163 }
164
165 json = ast_json_pack("{s: s}",
166 "foo", "bar");
167
168 /* Test for single channel */
170 ast_test_validate(test, NULL != blob);
171 ast_test_validate(test, NULL != ast_multi_channel_blob_get_json(blob));
172
173 return AST_TEST_PASS;
174}
175
176AST_TEST_DEFINE(multi_channel_blob_snapshots)
177{
179 RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
180 RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
181 RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
182 RAII_VAR(struct ast_channel *, chan_charlie, NULL, safe_channel_release);
183 struct ast_channel_snapshot *snapshot;
184 struct ao2_container *matches;
185
186 switch (cmd) {
187 case TEST_INIT:
188 info->name = __func__;
189 info->category = test_category;
190 info->summary = "Test creation of ast_multi_channel_blob objects";
191 info->description = "Test creation of ast_multi_channel_blob objects";
192 return AST_TEST_NOT_RUN;
193 case TEST_EXECUTE:
194 break;
195 }
196
197 json = ast_json_pack("{s: s}",
198 "type", "test");
199 chan_alice = ast_channel_alloc(0, AST_STATE_DOWN, "100", "Alice", "100", "100", "default", NULL, NULL, 0, "TEST/Alice");
200 ast_channel_unlock(chan_alice);
201 chan_bob = ast_channel_alloc(0, AST_STATE_DOWN, "200", "Bob", "200", "200", "default", NULL, NULL, 0, "TEST/Bob");
202 ast_channel_unlock(chan_bob);
203 chan_charlie = ast_channel_alloc(0, AST_STATE_DOWN, "300", "Bob", "300", "300", "default", NULL, NULL, 0, "TEST/Charlie");
204 ast_channel_unlock(chan_charlie);
205
207 ast_channel_lock(chan_alice);
209 ast_channel_unlock(chan_alice);
210 ast_channel_lock(chan_bob);
212 ast_channel_unlock(chan_bob);
213 ast_channel_lock(chan_charlie);
215 ast_channel_unlock(chan_charlie);
216
217 /* Test for unknown role */
218 ast_test_validate(test, NULL == ast_multi_channel_blob_get_channel(blob, "Foobar"));
219
220 /* Test for single match */
221 snapshot = ast_multi_channel_blob_get_channel(blob, "Caller");
222 ast_test_validate(test, NULL != snapshot);
223 ast_test_validate(test, 0 == strcmp("TEST/Alice", snapshot->base->name));
224
225 /* Test for single match, multiple possibilities */
226 snapshot = ast_multi_channel_blob_get_channel(blob, "Peer");
227 ast_test_validate(test, NULL != snapshot);
228 ast_test_validate(test, 0 != strcmp("TEST/Alice", snapshot->base->name));
229
230 /* Multi-match */
231 matches = ast_multi_channel_blob_get_channels(blob, "Peer");
232 ast_test_validate(test, NULL != matches);
233 ast_test_validate(test, 2 == ao2_container_count(matches));
234 snapshot = ao2_find(matches, "TEST/Bob", OBJ_KEY);
235 ast_test_validate(test, NULL != snapshot);
236 ao2_cleanup(snapshot);
237 snapshot = ao2_find(matches, "TEST/Charlie", OBJ_KEY);
238 ast_test_validate(test, NULL != snapshot);
239 ao2_cleanup(snapshot);
240 ast_test_validate(test, 1 == ao2_ref(matches, 0));
241 ao2_cleanup(matches);
242
243 return AST_TEST_PASS;
244}
245
246AST_TEST_DEFINE(channel_snapshot_json)
247{
248 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
250 RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
251 RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
252 RAII_VAR(struct ast_json *, actual, NULL, ast_json_unref);
253
254 switch (cmd) {
255 case TEST_INIT:
256 info->name = __func__;
257 info->category = test_category;
258 info->summary = "Test creation of ast_channel_blob objects";
259 info->description = "Test creation of ast_channel_blob objects";
260 return AST_TEST_NOT_RUN;
261 case TEST_EXECUTE:
262 break;
263 }
264
265 ast_test_validate(test, NULL == ast_channel_snapshot_to_json(NULL, NULL));
266
267 chan = ast_channel_alloc(0, AST_STATE_DOWN, "cid_num", "cid_name", "acctcode", "exten", "context", NULL, NULL, 0, "TEST/name");
268 ast_channel_unlock(chan);
269 ast_test_validate(test, NULL != chan);
270 ast_channel_lock(chan);
271 snapshot = ast_channel_snapshot_create(chan);
272 ast_channel_unlock(chan);
273 ast_test_validate(test, NULL != snapshot);
274
275 actual = ast_channel_snapshot_to_json(snapshot, NULL);
276 expected = ast_json_pack("{ s: s, s: s, s: s, s: s, s: s,"
277 " s: { s: s, s: s, s: i, s: s, s: s },"
278 " s: { s: s, s: s },"
279 " s: { s: s, s: s },"
280 " s: s"
281 " s: o"
282 "}",
283 "name", "TEST/name",
284 "state", "Down",
285 "accountcode", "acctcode",
286 "id", ast_channel_uniqueid(chan),
287 "protocol_id", "",
288 "dialplan",
289 "context", "context",
290 "exten", "exten",
291 "priority", 1,
292 "app_name", "",
293 "app_data", "",
294 "caller",
295 "name", "cid_name",
296 "number", "cid_num",
297 "connected",
298 "name", "",
299 "number", "",
300 "language", "en",
301 "creationtime",
304
305 ast_test_validate(test, ast_json_equal(expected, actual));
306
307 return AST_TEST_PASS;
308}
309
310AST_TEST_DEFINE(channel_redirect_snapshot_json)
311{
312 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
314 RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
315 RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
316 RAII_VAR(struct ast_json *, actual, NULL, ast_json_unref);
317 struct ast_party_redirecting data;
318
319
320 switch (cmd) {
321 case TEST_INIT:
322 info->name = __func__;
323 info->category = test_category;
324 info->summary = "Test creation of ast_channel_blob objects with rdnis";
325 info->description = "Test creation of ast_channel_blob objects with rdnis";
326 return AST_TEST_NOT_RUN;
327 case TEST_EXECUTE:
328 break;
329 }
330
331 ast_test_validate(test, NULL == ast_channel_snapshot_to_json(NULL, NULL));
332 chan = ast_channel_alloc(0, AST_STATE_DOWN, "cid_num", "cid_name", "acctcode", "exten", "context", NULL, NULL, 0, "TEST/name");
333 ast_channel_unlock(chan);
334 ast_test_validate(test, NULL != chan);
335
336 ast_channel_lock(chan);
338 data.from.number.valid = 1;
339 data.from.number.str = ast_strdup("123456");
340 ast_channel_set_redirecting(chan, &data, NULL);
342 ast_channel_unlock(chan);
343
344 ast_channel_lock(chan);
345 snapshot = ast_channel_snapshot_create(chan);
346 ast_channel_unlock(chan);
347 ast_test_validate(test, NULL != snapshot);
348
349 actual = ast_channel_snapshot_to_json(snapshot, NULL);
350 expected = ast_json_pack("{ s: s, s: s, s: s, s: s, s: s,"
351 " s: { s: s, s: s, s: i, s: s, s: s },"
352 " s: { s: s, s: s },"
353 " s: { s: s, s: s },"
354 " s: s"
355 " s: s"
356 " s: o"
357 "}",
358 "name", "TEST/name",
359 "state", "Down",
360 "accountcode", "acctcode",
361 "id", ast_channel_uniqueid(chan),
362 "protocol_id", "",
363 "dialplan",
364 "context", "context",
365 "exten", "exten",
366 "priority", 1,
367 "app_name", "",
368 "app_data", "",
369 "caller",
370 "name", "cid_name",
371 "number", "cid_num",
372 "connected",
373 "name", "",
374 "number", "",
375 "language", "en",
376 "caller_rdnis", "123456",
377 "creationtime",
380
381 ast_test_validate(test, ast_json_equal(expected, actual));
382
383 return AST_TEST_PASS;
384}
385
386static int unload_module(void)
387{
388 AST_TEST_UNREGISTER(channel_blob_create);
389 AST_TEST_UNREGISTER(null_blob);
390 AST_TEST_UNREGISTER(multi_channel_blob_create);
391 AST_TEST_UNREGISTER(multi_channel_blob_snapshots);
392 AST_TEST_UNREGISTER(channel_snapshot_json);
393 AST_TEST_UNREGISTER(channel_redirect_snapshot_json);
394
395 return 0;
396}
397
398static int load_module(void)
399{
400 AST_TEST_REGISTER(channel_blob_create);
401 AST_TEST_REGISTER(null_blob);
402 AST_TEST_REGISTER(multi_channel_blob_create);
403 AST_TEST_REGISTER(multi_channel_blob_snapshots);
404 AST_TEST_REGISTER(channel_snapshot_json);
405 AST_TEST_REGISTER(channel_redirect_snapshot_json);
406
408}
409
410AST_MODULE_INFO(ASTERISK_GPL_KEY, 0, "Stasis Channel Testing",
411 .support_level = AST_MODULE_SUPPORT_CORE,
412 .load = load_module,
413 .unload = unload_module
Asterisk main include file. File version handling, generic pbx functions.
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define OBJ_KEY
Definition: astobj2.h:1151
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
static const char type[]
Definition: chan_ooh323.c:109
General Asterisk PBX channel definitions.
void ast_party_redirecting_init(struct ast_party_redirecting *init)
Initialize the given redirecting structure.
Definition: channel.c:2141
void ast_channel_set_redirecting(struct ast_channel *chan, const struct ast_party_redirecting *redirecting, const struct ast_set_party_redirecting *update)
Set the redirecting id information in the Asterisk channel.
Definition: channel.c:9141
#define ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, assignedids, requestor, amaflag,...)
Create a channel structure.
Definition: channel.h:1299
#define ast_channel_lock(chan)
Definition: channel.h:2968
const char * ast_channel_uniqueid(const struct ast_channel *chan)
struct timeval ast_channel_creationtime(struct ast_channel *chan)
struct ast_channel * ast_channel_release(struct ast_channel *chan)
Unlink and release reference to a channel.
Definition: channel.c:1603
void ast_party_redirecting_free(struct ast_party_redirecting *doomed)
Destroy the redirecting information contents.
Definition: channel.c:2198
#define ast_channel_unlock(chan)
Definition: channel.h:2969
@ AST_STATE_DOWN
Definition: channelstate.h:36
struct ast_multi_channel_blob * ast_multi_channel_blob_create(struct ast_json *blob)
Create a ast_multi_channel_blob suitable for a stasis_message.
struct ast_channel_snapshot * ast_multi_channel_blob_get_channel(struct ast_multi_channel_blob *obj, const char *role)
Retrieve a channel snapshot associated with a specific role from a ast_multi_channel_blob.
struct ast_channel_snapshot * ast_channel_snapshot_create(struct ast_channel *chan)
Generate a snapshot of the channel state. This is an ao2 object, so ao2_cleanup() to deallocate.
struct ao2_container * ast_multi_channel_blob_get_channels(struct ast_multi_channel_blob *obj, const char *role)
Retrieve all channel snapshots associated with a specific role from a ast_multi_channel_blob.
void ast_multi_channel_blob_add_channel(struct ast_multi_channel_blob *obj, const char *role, struct ast_channel_snapshot *snapshot)
Add a ast_channel_snapshot to a ast_multi_channel_blob object.
struct ast_json * ast_multi_channel_blob_get_json(struct ast_multi_channel_blob *obj)
Retrieve the JSON blob from a ast_multi_channel_blob. Returned ast_json is still owned by obj.
struct stasis_message * ast_channel_blob_create(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
Creates a ast_channel_blob message.
struct ast_json * ast_json_null(void)
Get the JSON null value.
Definition: json.c:248
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
int ast_json_equal(const struct ast_json *lhs, const struct ast_json *rhs)
Compare two JSON objects.
Definition: json.c:357
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:612
struct ast_json * ast_json_timeval(const struct timeval tv, const char *zone)
Construct a timeval as JSON.
Definition: json.c:670
Asterisk module definitions.
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:557
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
def info(msg)
#define NULL
Definition: resample.c:96
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
enum stasis_message_type_result stasis_message_type_create(const char *name, struct stasis_message_vtable *vtable, struct stasis_message_type **result)
Create a new message type.
@ STASIS_MESSAGE_TYPE_SUCCESS
Definition: stasis.h:287
struct ast_json * ast_channel_snapshot_to_json(const struct ast_channel_snapshot *snapshot, const struct stasis_message_sanitizer *sanitize)
Build a JSON object from a ast_channel_snapshot.
Generic container type.
Blob of data associated with a channel.
struct ast_json * blob
const ast_string_field name
Structure representing a snapshot of channel state.
struct ast_channel_snapshot_base * base
Main Channel structure associated with a channel.
Abstract JSON element (object, array, string, int, ...).
A multi channel blob data structure for multi_channel_blob stasis messages.
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:344
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:299
char * str
Subscriber phone number (Malloced)
Definition: channel.h:293
Redirecting Line information. RDNIS (Redirecting Directory Number Information Service) Where a call d...
Definition: channel.h:524
struct ast_party_id from
Who is redirecting the call (Sent to the party the call is redirected toward)
Definition: channel.h:529
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
AST_TEST_DEFINE(channel_blob_create)
static void safe_channel_release(struct ast_channel *chan)
static int load_module(void)
static int unload_module(void)
static const char * test_category
#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