Add channel locking for channel snapshot creation.
[asterisk/asterisk.git] / tests / test_stasis_channels.c
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 \brief Test Stasis Channel messages and objects
21  *
22  * \author\verbatim Matt Jordan <mjordan@digium.com> \endverbatim
23  *
24  * \ingroup tests
25  */
26
27 /*** MODULEINFO
28         <depend>TEST_FRAMEWORK</depend>
29         <support_level>core</support_level>
30  ***/
31
32 #include "asterisk.h"
33
34 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
35
36 #include "asterisk/astobj2.h"
37 #include "asterisk/module.h"
38 #include "asterisk/stasis.h"
39 #include "asterisk/stasis_message_router.h"
40 #include "asterisk/test.h"
41 #include "asterisk/stasis_channels.h"
42 #include "asterisk/channel.h"
43
44 static const char *test_category = "/stasis/channels/";
45
46 static void safe_channel_release(struct ast_channel *chan)
47 {
48         if (!chan) {
49                 return;
50         }
51         ast_channel_release(chan);
52 }
53
54 AST_TEST_DEFINE(channel_blob_create)
55 {
56         struct ast_channel_blob *blob;
57         RAII_VAR(struct stasis_message_type *, type, NULL, ao2_cleanup);
58         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
59         RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
60         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
61         RAII_VAR(struct ast_json *, bad_json, NULL, ast_json_unref);
62
63         switch (cmd) {
64         case TEST_INIT:
65                 info->name = __func__;
66                 info->category = test_category;
67                 info->summary = "Test creation of ast_channel_blob objects";
68                 info->description = "Test creation of ast_channel_blob objects";
69                 return AST_TEST_NOT_RUN;
70         case TEST_EXECUTE:
71                 break;
72         }
73
74         type = stasis_message_type_create("test-type", NULL);
75         chan = ast_channel_alloc(0, AST_STATE_DOWN, "100", "Alice", "100", "100", "default", 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);
85         ast_channel_unlock(chan);
86         ast_test_validate(test, NULL != msg);
87         blob = stasis_message_data(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);
99         blob = stasis_message_data(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
108 AST_TEST_DEFINE(null_blob)
109 {
110         struct ast_channel_blob *blob;
111         RAII_VAR(struct stasis_message_type *, type, NULL, ao2_cleanup);
112         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
113         RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
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         type = stasis_message_type_create("test-type", NULL);
129         chan = ast_channel_alloc(0, AST_STATE_DOWN, "100", "Alice", "100", "100", "default", NULL, 0, "TEST/Alice");
130         json = ast_json_pack("{s: s}",
131                      "foo", "bar");
132
133         /* Test for single channel */
134         ast_channel_lock(chan);
135         msg = ast_channel_blob_create(chan, type, NULL);
136         ast_channel_unlock(chan);
137         ast_test_validate(test, NULL != msg);
138         blob = stasis_message_data(msg);
139         ast_test_validate(test, NULL != blob);
140         ast_test_validate(test, NULL != blob->snapshot);
141         ast_test_validate(test, ast_json_null() == blob->blob);
142         ast_test_validate(test, type == stasis_message_type(msg));
143
144         return AST_TEST_PASS;
145 }
146
147 AST_TEST_DEFINE(multi_channel_blob_create)
148 {
149         RAII_VAR(struct ast_multi_channel_blob *, blob, NULL, ao2_cleanup);
150         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
151         RAII_VAR(struct ast_json *, bad_json, NULL, ast_json_unref);
152
153         switch (cmd) {
154         case TEST_INIT:
155                 info->name = __func__;
156                 info->category = test_category;
157                 info->summary = "Test creation of ast_multi_channel_blob objects";
158                 info->description = "Test creation of ast_multi_channel_blob objects";
159                 return AST_TEST_NOT_RUN;
160         case TEST_EXECUTE:
161                 break;
162         }
163
164         json = ast_json_pack("{s: s}",
165                      "foo", "bar");
166
167         /* Test for single channel */
168         blob = ast_multi_channel_blob_create(json);
169         ast_test_validate(test, NULL != blob);
170         ast_test_validate(test, NULL != ast_multi_channel_blob_get_json(blob));
171
172         return AST_TEST_PASS;
173 }
174
175 AST_TEST_DEFINE(multi_channel_blob_snapshots)
176 {
177         RAII_VAR(struct ast_multi_channel_blob *, blob, NULL, ao2_cleanup);
178         RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
179         RAII_VAR(struct ast_channel *, chan_alice, NULL, safe_channel_release);
180         RAII_VAR(struct ast_channel *, chan_bob, NULL, safe_channel_release);
181         RAII_VAR(struct ast_channel *, chan_charlie, NULL, safe_channel_release);
182         struct ast_channel_snapshot *snapshot;
183         struct ao2_container *matches;
184
185         switch (cmd) {
186         case TEST_INIT:
187                 info->name = __func__;
188                 info->category = test_category;
189                 info->summary = "Test creation of ast_multi_channel_blob objects";
190                 info->description = "Test creation of ast_multi_channel_blob objects";
191                 return AST_TEST_NOT_RUN;
192         case TEST_EXECUTE:
193                 break;
194         }
195
196         json = ast_json_pack("{s: s}",
197                      "type", "test");
198         chan_alice = ast_channel_alloc(0, AST_STATE_DOWN, "100", "Alice", "100", "100", "default", NULL, 0, "TEST/Alice");
199         chan_bob = ast_channel_alloc(0, AST_STATE_DOWN, "200", "Bob", "200", "200", "default", NULL, 0, "TEST/Bob");
200         chan_charlie = ast_channel_alloc(0, AST_STATE_DOWN, "300", "Bob", "300", "300", "default", NULL, 0, "TEST/Charlie");
201
202         blob = ast_multi_channel_blob_create(json);
203         ast_channel_lock(chan_alice);
204         ast_multi_channel_blob_add_channel(blob, "Caller", ast_channel_snapshot_create(chan_alice));
205         ast_channel_unlock(chan_alice);
206         ast_channel_lock(chan_bob);
207         ast_multi_channel_blob_add_channel(blob, "Peer", ast_channel_snapshot_create(chan_bob));
208         ast_channel_unlock(chan_bob);
209         ast_channel_lock(chan_charlie);
210         ast_multi_channel_blob_add_channel(blob, "Peer", ast_channel_snapshot_create(chan_charlie));
211         ast_channel_unlock(chan_charlie);
212
213         /* Test for unknown role */
214         ast_test_validate(test, NULL == ast_multi_channel_blob_get_channel(blob, "Foobar"));
215
216         /* Test for single match */
217         snapshot = ast_multi_channel_blob_get_channel(blob, "Caller");
218         ast_test_validate(test, NULL != snapshot);
219         ast_test_validate(test, 0 == strcmp("TEST/Alice", snapshot->name));
220
221         /* Test for single match, multiple possibilities */
222         snapshot = ast_multi_channel_blob_get_channel(blob, "Peer");
223         ast_test_validate(test, NULL != snapshot);
224         ast_test_validate(test, 0 != strcmp("TEST/Alice", snapshot->name));
225
226         /* Multi-match */
227         matches = ast_multi_channel_blob_get_channels(blob, "Peer");
228         ast_test_validate(test, NULL != matches);
229         ast_test_validate(test, 2 == ao2_container_count(matches));
230         snapshot = ao2_find(matches, "TEST/Bob", OBJ_KEY);
231         ast_test_validate(test, NULL != snapshot);
232         ao2_cleanup(snapshot);
233         snapshot = ao2_find(matches, "TEST/Charlie", OBJ_KEY);
234         ast_test_validate(test, NULL != snapshot);
235         ao2_cleanup(snapshot);
236         ast_test_validate(test, 1 == ao2_ref(matches, 0));
237         ao2_cleanup(matches);
238
239         return AST_TEST_PASS;
240 }
241
242 AST_TEST_DEFINE(channel_snapshot_json)
243 {
244         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
245         RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
246         RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
247         RAII_VAR(struct ast_json *, expected, NULL, ast_json_unref);
248         RAII_VAR(struct ast_json *, actual, NULL, ast_json_unref);
249
250         switch (cmd) {
251         case TEST_INIT:
252                 info->name = __func__;
253                 info->category = test_category;
254                 info->summary = "Test creation of ast_channel_blob objects";
255                 info->description = "Test creation of ast_channel_blob objects";
256                 return AST_TEST_NOT_RUN;
257         case TEST_EXECUTE:
258                 break;
259         }
260
261         ast_test_validate(test, NULL == ast_channel_snapshot_to_json(NULL, NULL));
262
263         chan = ast_channel_alloc(0, AST_STATE_DOWN, "cid_num", "cid_name", "acctcode", "exten", "context", NULL, 0, "TEST/name");
264         ast_test_validate(test, NULL != chan);
265         ast_channel_lock(chan);
266         snapshot = ast_channel_snapshot_create(chan);
267         ast_channel_unlock(chan);
268         ast_test_validate(test, NULL != snapshot);
269
270         actual = ast_channel_snapshot_to_json(snapshot, NULL);
271         expected = ast_json_pack("{ s: s, s: s, s: s, s: s,"
272                                  "  s: { s: s, s: s, s: i },"
273                                  "  s: { s: s, s: s },"
274                                  "  s: { s: s, s: s },"
275                                  "  s: o"
276                                  "}",
277                                  "name", "TEST/name",
278                                  "state", "Down",
279                                  "accountcode", "acctcode",
280                                  "id", ast_channel_uniqueid(chan),
281                                  "dialplan",
282                                  "context", "context",
283                                  "exten", "exten",
284                                  "priority", 1,
285                                  "caller",
286                                  "name", "cid_name",
287                                  "number", "cid_num",
288                                  "connected",
289                                  "name", "",
290                                  "number", "",
291                                  "creationtime",
292                                  ast_json_timeval(
293                                          ast_channel_creationtime(chan), NULL));
294
295         ast_test_validate(test, ast_json_equal(expected, actual));
296
297         return AST_TEST_PASS;
298 }
299
300 static int unload_module(void)
301 {
302         AST_TEST_UNREGISTER(channel_blob_create);
303         AST_TEST_UNREGISTER(null_blob);
304         AST_TEST_UNREGISTER(multi_channel_blob_create);
305         AST_TEST_UNREGISTER(multi_channel_blob_snapshots);
306         AST_TEST_UNREGISTER(channel_snapshot_json);
307
308         return 0;
309 }
310
311 static int load_module(void)
312 {
313         AST_TEST_REGISTER(channel_blob_create);
314         AST_TEST_REGISTER(null_blob);
315         AST_TEST_REGISTER(multi_channel_blob_create);
316         AST_TEST_REGISTER(multi_channel_blob_snapshots);
317         AST_TEST_REGISTER(channel_snapshot_json);
318
319         return AST_MODULE_LOAD_SUCCESS;
320 }
321
322 AST_MODULE_INFO(ASTERISK_GPL_KEY, 0, "Stasis Channel Testing",
323                 .load = load_module,
324                 .unload = unload_module
325         );