CI: Add pre-build merge back in as RECURSIVE
[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
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"
38 #include "asterisk/stasis_message_router.h"
39 #include "asterisk/test.h"
40 #include "asterisk/stasis_channels.h"
41 #include "asterisk/channel.h"
42
43 static const char *test_category = "/stasis/channels/";
44
45 static void safe_channel_release(struct ast_channel *chan)
46 {
47         if (!chan) {
48                 return;
49         }
50         ast_channel_release(chan);
51 }
52
53 AST_TEST_DEFINE(channel_blob_create)
54 {
55         struct ast_channel_blob *blob;
56         RAII_VAR(struct stasis_message_type *, type, NULL, ao2_cleanup);
57         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
58         RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
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");
75         ast_channel_unlock(chan);
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         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);
139         blob = stasis_message_data(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
148 AST_TEST_DEFINE(multi_channel_blob_create)
149 {
150         RAII_VAR(struct ast_multi_channel_blob *, blob, NULL, ao2_cleanup);
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 */
169         blob = ast_multi_channel_blob_create(json);
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
176 AST_TEST_DEFINE(multi_channel_blob_snapshots)
177 {
178         RAII_VAR(struct ast_multi_channel_blob *, blob, NULL, ao2_cleanup);
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
206         blob = ast_multi_channel_blob_create(json);
207         ast_channel_lock(chan_alice);
208         ast_multi_channel_blob_add_channel(blob, "Caller", ast_channel_snapshot_create(chan_alice));
209         ast_channel_unlock(chan_alice);
210         ast_channel_lock(chan_bob);
211         ast_multi_channel_blob_add_channel(blob, "Peer", ast_channel_snapshot_create(chan_bob));
212         ast_channel_unlock(chan_bob);
213         ast_channel_lock(chan_charlie);
214         ast_multi_channel_blob_add_channel(blob, "Peer", ast_channel_snapshot_create(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->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->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
246 AST_TEST_DEFINE(channel_snapshot_json)
247 {
248         RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
249         RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_release);
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,"
277                                  "  s: { s: s, s: s, s: i },"
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                                  "dialplan",
288                                  "context", "context",
289                                  "exten", "exten",
290                                  "priority", 1,
291                                  "caller",
292                                  "name", "cid_name",
293                                  "number", "cid_num",
294                                  "connected",
295                                  "name", "",
296                                  "number", "",
297                                  "language", "en",
298                                  "creationtime",
299                                  ast_json_timeval(
300                                          ast_channel_creationtime(chan), NULL));
301
302         ast_test_validate(test, ast_json_equal(expected, actual));
303
304         return AST_TEST_PASS;
305 }
306
307 static int unload_module(void)
308 {
309         AST_TEST_UNREGISTER(channel_blob_create);
310         AST_TEST_UNREGISTER(null_blob);
311         AST_TEST_UNREGISTER(multi_channel_blob_create);
312         AST_TEST_UNREGISTER(multi_channel_blob_snapshots);
313         AST_TEST_UNREGISTER(channel_snapshot_json);
314
315         return 0;
316 }
317
318 static int load_module(void)
319 {
320         AST_TEST_REGISTER(channel_blob_create);
321         AST_TEST_REGISTER(null_blob);
322         AST_TEST_REGISTER(multi_channel_blob_create);
323         AST_TEST_REGISTER(multi_channel_blob_snapshots);
324         AST_TEST_REGISTER(channel_snapshot_json);
325
326         return AST_MODULE_LOAD_SUCCESS;
327 }
328
329 AST_MODULE_INFO(ASTERISK_GPL_KEY, 0, "Stasis Channel Testing",
330         .load = load_module,
331         .unload = unload_module
332 );