c6cafd6ad998cce7bc07e2d948c02a1bd8189d93
[asterisk/asterisk.git] / tests / test_stasis_endpoints.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * David M. Lee, II <dlee@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 endpoints.
21  *
22  * \author\verbatim David M. Lee, II <dlee@digium.com> \endverbatim
23  *
24  * \ingroup tests
25  */
26
27 /*** MODULEINFO
28         <depend>TEST_FRAMEWORK</depend>
29         <depend>res_stasis_test</depend>
30         <support_level>core</support_level>
31  ***/
32
33 #include "asterisk.h"
34
35 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
36
37 #include "asterisk/astobj2.h"
38 #include "asterisk/channel.h"
39 #include "asterisk/endpoints.h"
40 #include "asterisk/module.h"
41 #include "asterisk/stasis_channels.h"
42 #include "asterisk/stasis_endpoints.h"
43 #include "asterisk/stasis_test.h"
44 #include "asterisk/test.h"
45
46 static const char *test_category = "/stasis/endpoints/";
47
48 static void safe_channel_hangup(struct ast_channel *chan)
49 {
50         if (!chan) {
51                 return;
52         }
53         ast_hangup(chan);
54 }
55
56 /*! \brief Message matcher looking for cache update messages */
57 static int cache_update(struct stasis_message *msg, const void *data) {
58         struct stasis_cache_update *update;
59         struct ast_endpoint_snapshot *snapshot;
60         const char *name = data;
61
62         if (stasis_cache_update_type() != stasis_message_type(msg)) {
63                 return 0;
64         }
65
66         update = stasis_message_data(msg);
67         if (ast_endpoint_snapshot_type() != update->type) {
68                 return 0;
69         }
70
71         snapshot = stasis_message_data(update->old_snapshot);
72         if (!snapshot) {
73                 snapshot = stasis_message_data(update->new_snapshot);
74         }
75
76         return 0 == strcmp(name, snapshot->resource);
77 }
78
79 AST_TEST_DEFINE(state_changes)
80 {
81         RAII_VAR(struct ast_endpoint *, uut, NULL, ast_endpoint_shutdown);
82         RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_hangup);
83         RAII_VAR(struct stasis_message_sink *, sink, NULL, ao2_cleanup);
84         RAII_VAR(struct stasis_subscription *, sub, NULL, stasis_unsubscribe);
85         struct stasis_message *msg;
86         struct stasis_message_type *type;
87         struct ast_endpoint_snapshot *actual_snapshot;
88         int actual_count;
89
90         switch (cmd) {
91         case TEST_INIT:
92                 info->name = __func__;
93                 info->category = test_category;
94                 info->summary = "Test endpoint updates as its state changes";
95                 info->description =
96                         "Test endpoint updates as its state changes";
97                 return AST_TEST_NOT_RUN;
98         case TEST_EXECUTE:
99                 break;
100         }
101
102         uut = ast_endpoint_create("TEST", __func__);
103         ast_test_validate(test, NULL != uut);
104
105         sink = stasis_message_sink_create();
106         ast_test_validate(test, NULL != sink);
107
108         sub = stasis_subscribe(ast_endpoint_topic(uut),
109                 stasis_message_sink_cb(), sink);
110         ast_test_validate(test, NULL != sub);
111
112         ast_endpoint_set_state(uut, AST_ENDPOINT_OFFLINE);
113         actual_count = stasis_message_sink_wait_for_count(sink, 1,
114                 STASIS_SINK_DEFAULT_WAIT);
115         ast_test_validate(test, 1 == actual_count);
116         msg = sink->messages[0];
117         type = stasis_message_type(msg);
118         ast_test_validate(test, ast_endpoint_snapshot_type() == type);
119         actual_snapshot = stasis_message_data(msg);
120         ast_test_validate(test, AST_ENDPOINT_OFFLINE == actual_snapshot->state);
121
122         ast_endpoint_set_max_channels(uut, 8675309);
123         actual_count = stasis_message_sink_wait_for_count(sink, 2,
124                 STASIS_SINK_DEFAULT_WAIT);
125         ast_test_validate(test, 2 == actual_count);
126         msg = sink->messages[1];
127         type = stasis_message_type(msg);
128         ast_test_validate(test, ast_endpoint_snapshot_type() == type);
129         actual_snapshot = stasis_message_data(msg);
130         ast_test_validate(test, 8675309 == actual_snapshot->max_channels);
131
132         return AST_TEST_PASS;
133 }
134
135 AST_TEST_DEFINE(cache_clear)
136 {
137         RAII_VAR(struct ast_endpoint *, uut, NULL, ast_endpoint_shutdown);
138         RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_hangup);
139         RAII_VAR(struct stasis_message_sink *, sink, NULL, ao2_cleanup);
140         RAII_VAR(struct stasis_subscription *, sub, NULL, stasis_unsubscribe);
141         struct stasis_message *msg;
142         struct stasis_message_type *type;
143         struct ast_endpoint_snapshot *actual_snapshot;
144         struct stasis_cache_update *update;
145         int message_index;
146
147         switch (cmd) {
148         case TEST_INIT:
149                 info->name = __func__;
150                 info->category = test_category;
151                 info->summary = "Test endpoint state change messages";
152                 info->description = "Test endpoint state change messages";
153                 return AST_TEST_NOT_RUN;
154         case TEST_EXECUTE:
155                 break;
156         }
157
158         /* Subscribe to the cache topic */
159         sink = stasis_message_sink_create();
160         ast_test_validate(test, NULL != sink);
161
162         sub = stasis_subscribe(
163                 stasis_caching_get_topic(ast_endpoint_topic_all_cached()),
164                 stasis_message_sink_cb(), sink);
165         ast_test_validate(test, NULL != sub);
166
167         uut = ast_endpoint_create("TEST", __func__);
168         ast_test_validate(test, NULL != uut);
169
170         /* Since the cache topic is a singleton (ew), it may have messages from
171          * elsewheres that it's processing, or maybe even some final messages
172          * from the prior test. We've got to wait_for our specific message,
173          * instead of wait_for_count.
174          */
175         message_index = stasis_message_sink_wait_for(sink, 0,
176                 cache_update, __func__, STASIS_SINK_DEFAULT_WAIT);
177         ast_test_validate(test, 0 <= message_index);
178
179         /* First message should be a cache creation entry for our endpont */
180         msg = sink->messages[message_index];
181         type = stasis_message_type(msg);
182         ast_test_validate(test, stasis_cache_update_type() == type);
183         update = stasis_message_data(msg);
184         ast_test_validate(test, ast_endpoint_snapshot_type() == update->type);
185         ast_test_validate(test, NULL == update->old_snapshot);
186         actual_snapshot = stasis_message_data(update->new_snapshot);
187         ast_test_validate(test, 0 == strcmp("TEST", actual_snapshot->tech));
188         ast_test_validate(test,
189                 0 == strcmp(__func__, actual_snapshot->resource));
190
191         ast_endpoint_shutdown(uut);
192         uut = NULL;
193         message_index = stasis_message_sink_wait_for(sink, message_index + 1,
194                 cache_update, __func__, STASIS_SINK_DEFAULT_WAIT);
195         ast_test_validate(test, 0 <= message_index);
196         /* Now we should have a cache removal entry */
197         msg = sink->messages[message_index];
198         type = stasis_message_type(msg);
199         ast_test_validate(test, stasis_cache_update_type() == type);
200         update = stasis_message_data(msg);
201         ast_test_validate(test, ast_endpoint_snapshot_type() == update->type);
202         actual_snapshot = stasis_message_data(update->old_snapshot);
203         ast_test_validate(test, 0 == strcmp("TEST", actual_snapshot->tech));
204         ast_test_validate(test,
205                 0 == strcmp(__func__, actual_snapshot->resource));
206         ast_test_validate(test, NULL == update->new_snapshot);
207
208         return AST_TEST_PASS;
209 }
210
211 AST_TEST_DEFINE(channel_messages)
212 {
213         RAII_VAR(struct ast_endpoint *, uut, NULL, ast_endpoint_shutdown);
214         RAII_VAR(struct ast_channel *, chan, NULL, safe_channel_hangup);
215         RAII_VAR(struct stasis_message_sink *, sink, NULL, ao2_cleanup);
216         RAII_VAR(struct stasis_subscription *, sub, NULL, stasis_unsubscribe);
217         struct stasis_message *msg;
218         struct stasis_message_type *type;
219         struct ast_endpoint_snapshot *actual_snapshot;
220         int actual_count;
221
222         switch (cmd) {
223         case TEST_INIT:
224                 info->name = __func__;
225                 info->category = test_category;
226                 info->summary = "Test channel messages on an endpoint topic";
227                 info->description =
228                         "Test channel messages on an endpoint topic";
229                 return AST_TEST_NOT_RUN;
230         case TEST_EXECUTE:
231                 break;
232         }
233
234         uut = ast_endpoint_create("TEST", __func__);
235         ast_test_validate(test, NULL != uut);
236
237         sink = stasis_message_sink_create();
238         ast_test_validate(test, NULL != sink);
239
240         sub = stasis_subscribe(ast_endpoint_topic(uut),
241                 stasis_message_sink_cb(), sink);
242         ast_test_validate(test, NULL != sub);
243
244         chan = ast_channel_alloc(0, AST_STATE_DOWN, "100", __func__, "100",
245                 "100", "default", NULL, 0, "TEST/test_res");
246         ast_test_validate(test, NULL != chan);
247
248         ast_endpoint_add_channel(uut, chan);
249
250         actual_count = stasis_message_sink_wait_for_count(sink, 2,
251                 STASIS_SINK_DEFAULT_WAIT);
252         ast_test_validate(test, 2 == actual_count);
253
254         msg = sink->messages[0];
255         type = stasis_message_type(msg);
256         ast_test_validate(test, ast_channel_snapshot_type() == type);
257
258         msg = sink->messages[1];
259         type = stasis_message_type(msg);
260         ast_test_validate(test, ast_endpoint_snapshot_type() == type);
261         actual_snapshot = stasis_message_data(msg);
262         ast_test_validate(test, 1 == actual_snapshot->num_channels);
263
264         safe_channel_hangup(chan);
265         chan = NULL;
266
267         actual_count = stasis_message_sink_wait_for_count(sink, 5,
268                 STASIS_SINK_DEFAULT_WAIT);
269         ast_test_validate(test, 5 == actual_count);
270
271         msg = sink->messages[2];
272         type = stasis_message_type(msg);
273         ast_test_validate(test, ast_channel_snapshot_type() == type);
274
275         msg = sink->messages[3];
276         type = stasis_message_type(msg);
277         ast_test_validate(test, stasis_cache_clear_type() == type);
278
279         msg = sink->messages[4];
280         type = stasis_message_type(msg);
281         ast_test_validate(test, ast_endpoint_snapshot_type() == type);
282         actual_snapshot = stasis_message_data(msg);
283         ast_test_validate(test, 0 == actual_snapshot->num_channels);
284
285         return AST_TEST_PASS;
286 }
287
288 static int unload_module(void)
289 {
290         AST_TEST_UNREGISTER(state_changes);
291         AST_TEST_UNREGISTER(cache_clear);
292         AST_TEST_UNREGISTER(channel_messages);
293         return 0;
294 }
295
296 static int load_module(void)
297 {
298         AST_TEST_REGISTER(state_changes);
299         AST_TEST_REGISTER(cache_clear);
300         AST_TEST_REGISTER(channel_messages);
301         return AST_MODULE_LOAD_SUCCESS;
302 }
303
304 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Endpoint stasis-related testing",
305         .load = load_module,
306         .unload = unload_module,
307         .nonoptreq = "res_stasis_test",
308         );