Asterisk - The Open Source Telephony Project GIT-master-b023714
Loading...
Searching...
No Matches
test_mwi.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2019, Sangoma Technologies Corporation
5 *
6 * Kevin Harwell <kharwell@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/*** MODULEINFO
20 <depend>TEST_FRAMEWORK</depend>
21 <support_level>core</support_level>
22 ***/
23
24#include "asterisk.h"
25
26#include "asterisk/astobj2.h"
28#include "asterisk/module.h"
29#include "asterisk/mwi.h"
30#include "asterisk/stasis.h"
31#include "asterisk/test.h"
32
33#define test_category "/mwi/"
34
35#define MAILBOX_PREFIX "test~" /* Hopefully sufficiently unlikely */
36#define MAILBOX_COUNT 500
37#define MAILBOX_SIZE 32
38
41
42/*!
43 * For testing purposes each subscribed mailbox is a number. This value is
44 * the summation of all mailboxes.
45 */
46static size_t sum_total;
47
48/*! Test variable that tracks the running total of mailboxes */
49static size_t running_total;
50
51/*! This value is set to check if MWI data is zero before publishing */
52static int expect_zero;
53
54static int num_to_mailbox(char *mailbox, size_t size, size_t num)
55{
56 if (snprintf(mailbox, 10, MAILBOX_PREFIX "%zu", num) == -1) {
57 ast_log(LOG_ERROR, "Unable to convert mailbox to string\n");
58 return -1;
59 }
60
61 return 0;
62}
63
64static int mailbox_to_num(const char *mailbox, size_t *num)
65{
66 uintmax_t tmp;
67 const char *p = strchr(mailbox, '~');
68
69 if (!p) {
70 ast_log(LOG_ERROR, "Prefix separator '~' not found in '%s'\n", mailbox);
71 return -1;
72 }
73
74 if (ast_str_to_umax(++p, &tmp)) {
75 ast_log(LOG_ERROR, "Unable to convert mailbox '%s' to numeric\n", mailbox);
76 return -1;
77 }
78 *num = (size_t) tmp;
79
80 return 0;
81}
82
83static int validate_data(struct ast_mwi_state *mwi_state)
84{
85 size_t num;
86 size_t val;
87
88 if (mailbox_to_num(mwi_state->uniqueid, &num)) {
89 return -1;
90 }
91
92 running_total += num;
93
94 val = expect_zero ? 0 : num;
95
96 if (mwi_state->urgent_msgs != val || mwi_state->new_msgs != val ||
97 mwi_state->old_msgs != val) {
98 ast_log(LOG_ERROR, "Unexpected MWI state data for '%s', %d != %zu\n",
99 mwi_state->uniqueid, mwi_state->urgent_msgs, val);
100 return -1;
101 }
102
103 return num;
104}
105
106static void handle_validate(const char *mailbox, struct ast_mwi_subscriber *sub)
107{
108 struct ast_mwi_state *mwi_state = ast_mwi_subscriber_data(sub);
109
110 if (ast_begins_with(mwi_state->uniqueid, MAILBOX_PREFIX)) {
111 validate_data(mwi_state);
112 }
113
114 ao2_cleanup(mwi_state);
115}
116
119 .on_unsubscribe = handle_validate
120};
121
122static void mwi_type_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
123{
124 /* No op since we are not really testing stasis topic handling here */
125}
126
127static int subscriptions_destroy(struct subscriptions *subs)
128{
130
132 AST_VECTOR_FREE(subs);
133
135
136 if (running_total != sum_total) {
137 ast_log(LOG_ERROR, "Failed to destroy all MWI subscriptions: running=%zu, sum=%zu\n",
139 return -1;
140 }
141
142 return 0;
143}
144
145static int subscriptions_create(struct subscriptions *subs)
146{
147 size_t i;
148
151 return -1;
152 }
153
155 expect_zero = 1;
156
157 for (i = 0; i < MAILBOX_COUNT; ++i) {
158 struct ast_mwi_subscriber *sub;
159 char mailbox[MAILBOX_SIZE];
160
161 if (num_to_mailbox(mailbox, MAILBOX_SIZE, i)) {
162 break;
163 }
164
166 if (!sub) {
167 ast_log(LOG_ERROR, "Failed to create a MWI subscriber for mailbox '%s'\n", mailbox);
168 break;
169 }
170
171 if (AST_VECTOR_APPEND(subs, sub)) {
172 ast_log(LOG_ERROR, "Failed to add to MWI sub to vector for mailbox '%s'\n", mailbox);
173 ao2_ref(sub, -1);
174 break;
175 }
176
177 sum_total += i;
178 }
179
180 if (i != MAILBOX_COUNT || running_total != sum_total) {
181 ast_log(LOG_ERROR, "Failed to create all MWI subscriptions: running=%zu, sum=%zu\n",
184 return -1;
185 }
186
187 return 0;
188}
189
190static int publishers_destroy(struct publishers *pubs)
191{
192 size_t i;
193
194 if (pubs) {
195 /* Remove explicit publishers */
197 AST_VECTOR_FREE(pubs);
198 return 0;
199 }
200
201 for (i = 0; i < MAILBOX_COUNT; ++i) {
202 char mailbox[MAILBOX_SIZE];
203
204 /* Remove implicit publishers */
205 if (num_to_mailbox(mailbox, MAILBOX_SIZE, i)) {
206 return -1;
207 }
208
209 ast_delete_mwi_state(mailbox, NULL);
210 }
211
212 return 0;
213}
214
215static int publishers_create(struct publishers *pubs)
216{
217 size_t i;
218
219 if (AST_VECTOR_INIT(pubs, MAILBOX_COUNT)) {
220 return -1;
221 }
222
223 for (i = 0; i < MAILBOX_COUNT; ++i) {
224 struct ast_mwi_publisher *pub;
225 char mailbox[MAILBOX_SIZE];
226
227 if (num_to_mailbox(mailbox, MAILBOX_SIZE, i)) {
228 break;
229 }
230
231 /* Create the MWI publisher */
232 pub = ast_mwi_add_publisher(mailbox);
233 if (!pub) {
234 ast_log(LOG_ERROR, "Failed to create an MWI publisher for mailbox '%s'\n", mailbox);
235 break;
236 }
237
238 if (AST_VECTOR_APPEND(pubs, pub)) {
239 ast_log(LOG_ERROR, "Failed to add to an MWI publisher to vector for mailbox '%s'\n", mailbox);
240 ao2_ref(pub, -1);
241 break;
242 }
243 }
244
245 if (i != MAILBOX_COUNT) {
246 ast_log(LOG_ERROR, "Failed to create all MWI publishers: count=%zu\n", i);
247 publishers_destroy(pubs);
248 return -1;
249 }
250
251 return 0;
252}
253
254static int implicit_publish_cb(struct ast_mwi_state *mwi_state, void *data)
255{
256 size_t num;
257
258 if (!ast_begins_with(mwi_state->uniqueid, MAILBOX_PREFIX)) {
259 /* Ignore any mailboxes not prefixed */
260 return 0;
261 }
262
263 num = validate_data(mwi_state);
264 if (num < 0) {
265 return CMP_STOP;
266 }
267
268 ast_mwi_publish_by_mailbox(mwi_state->uniqueid, NULL, num, num, num, NULL, NULL);
269
270 return 0;
271}
272
273static int explicit_publish_cb(struct ast_mwi_state *mwi_state, void *data)
274{
275 struct publishers *pubs = data;
276 struct ast_mwi_publisher *pub;
277 size_t num;
278
279 if (!ast_begins_with(mwi_state->uniqueid, MAILBOX_PREFIX)) {
280 /* Ignore any mailboxes not prefixed */
281 return 0;
282 }
283
284 num = validate_data(mwi_state);
285 if (num < 0) {
286 return CMP_STOP;
287 }
288
289 if (mailbox_to_num(mwi_state->uniqueid, &num)) {
290 return CMP_STOP;
291 }
292
293 /* Mailbox number will always be the index */
294 pub = AST_VECTOR_GET(pubs, num);
295
296 if (!pub) {
297 ast_log(LOG_ERROR, "Unable to locate MWI publisher for mailbox '%s'\n", mwi_state->uniqueid);
298 return CMP_STOP;
299 }
300
301 ast_mwi_publish(pub, num, num, num, NULL, NULL);
302
303 return 0;
304}
305
306static int publish(on_mwi_state cb, void *user_data)
307{
308 /* First time there is no state data */
309 expect_zero = 1;
310
311 running_total = 0;
312 ast_mwi_state_callback_all(cb, user_data);
313
314 if (running_total != sum_total) {
315 ast_log(LOG_ERROR, "Failed MWI state callback (1): running=%zu, sum=%zu\n",
317 return -1;
318 }
319
320 /* Second time check valid state data exists */
322 ast_mwi_state_callback_all(cb, user_data);
323
324 if (running_total != sum_total) {
325 ast_log(LOG_ERROR, "Failed MWI state callback (2): running=%zu, sum=%zu\n",
327 return -1;
328 }
329
330 return 0;
331}
332
333AST_TEST_DEFINE(implicit_publish)
334{
335 struct subscriptions subs;
336 int rc = AST_TEST_PASS;
337
338 switch (cmd) {
339 case TEST_INIT:
340 info->name = __func__;
341 info->category = test_category;
342 info->summary = "Test implicit publishing of MWI state";
343 info->description = info->summary;
344 return AST_TEST_NOT_RUN;
345 case TEST_EXECUTE:
346 break;
347 }
348
349 ast_test_validate(test, !subscriptions_create(&subs));
350
351 ast_test_validate_cleanup(test, !publish(implicit_publish_cb, NULL),
352 rc, cleanup);
353
354cleanup:
356 return AST_TEST_FAIL;
357 }
358
359 return rc;
360}
361
362AST_TEST_DEFINE(explicit_publish)
363{
364 struct subscriptions subs;
365 struct publishers pubs;
366 int rc = AST_TEST_PASS;
367
368 switch (cmd) {
369 case TEST_INIT:
370 info->name = __func__;
371 info->category = test_category;
372 info->summary = "Test explicit publishing of MWI state";
373 info->description = info->summary;
374 return AST_TEST_NOT_RUN;
375 case TEST_EXECUTE:
376 break;
377 }
378
379 ast_test_validate(test, !subscriptions_create(&subs));
380 ast_test_validate_cleanup(test, !publishers_create(&pubs), rc, cleanup);
381
382 ast_test_validate_cleanup(test, !publish(explicit_publish_cb, &pubs),
383 rc, cleanup);
384
385cleanup:
386 if (subscriptions_destroy(&subs) || publishers_destroy(&pubs)) {
387 return AST_TEST_FAIL;
388 }
389
390 return rc;
391}
392
393static int unload_module(void)
394{
395 AST_TEST_UNREGISTER(implicit_publish);
396 AST_TEST_UNREGISTER(explicit_publish);
397
398 return 0;
399}
400
401static int load_module(void)
402{
403 AST_TEST_REGISTER(implicit_publish);
404 AST_TEST_REGISTER(explicit_publish);
405
407}
408
Asterisk main include file. File version handling, generic pbx functions.
#define ast_log
Definition astobj2.c:42
@ CMP_STOP
Definition astobj2.h:1028
#define ao2_cleanup(obj)
Definition astobj2.h:1934
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
Conversion utility functions.
int ast_str_to_umax(const char *str, uintmax_t *res)
Convert the given string to an unsigned max size integer.
#define LOG_ERROR
Asterisk module definitions.
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition module.h:581
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition module.h:70
Asterisk MWI API.
int(* on_mwi_state)(struct ast_mwi_state *mwi_state, void *data)
The delegate called for each managed mailbox state.
Definition mwi.h:301
void ast_mwi_state_callback_all(on_mwi_state handler, void *data)
For each managed mailbox call the given handler.
Definition mwi.c:338
struct ast_mwi_publisher * ast_mwi_add_publisher(const char *mailbox)
Add an MWI state publisher to the mailbox.
Definition mwi.c:295
int ast_mwi_add_observer(struct ast_mwi_observer *observer)
Add an observer to receive MWI state related events.
Definition mwi.c:301
int ast_mwi_publish(struct ast_mwi_publisher *publisher, int urgent_msgs, int new_msgs, int old_msgs, const char *channel_id, struct ast_eid *eid)
Publish MWI for the given mailbox.
Definition mwi.c:358
#define ast_delete_mwi_state(mailbox, context)
Delete MWI state cached by stasis.
Definition mwi.h:431
void ast_mwi_remove_observer(struct ast_mwi_observer *observer)
Remove an MWI state observer.
Definition mwi.c:307
void * ast_mwi_unsubscribe_and_join(struct ast_mwi_subscriber *sub)
Unsubscribe from the stasis topic, block until the final message is received, and then unsubscribe fr...
Definition mwi.c:259
struct ast_mwi_subscriber * ast_mwi_subscribe_pool(const char *mailbox, stasis_subscription_cb callback, void *data)
Add an MWI state subscriber, and stasis subscription to the mailbox.
Definition mwi.c:235
int ast_mwi_publish_by_mailbox(const char *mailbox, const char *context, int urgent_msgs, int new_msgs, int old_msgs, const char *channel_id, struct ast_eid *eid)
Publish MWI for the given mailbox.
Definition mwi.c:375
struct ast_mwi_state * ast_mwi_subscriber_data(struct ast_mwi_subscriber *sub)
Retrieves the state data object associated with the MWI subscriber.
Definition mwi.c:269
static struct stasis_subscription * sub
Statsd channel stats. Exmaple of how to subscribe to Stasis events.
unsigned char publish
static void cleanup(void)
Clean up any old apps that we don't need any more.
Definition res_stasis.c:327
#define NULL
Definition resample.c:96
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
static int force_inline attribute_pure ast_begins_with(const char *str, const char *prefix)
Checks whether a string begins with another.
Definition strings.h:97
MWI state event interface.
Definition mwi.h:248
void(* on_subscribe)(const char *mailbox, struct ast_mwi_subscriber *sub)
Raised when MWI is being subscribed.
Definition mwi.h:255
The structure that contains MWI state.
Definition mwi.h:455
int urgent_msgs
Definition mwi.h:464
int old_msgs
Definition mwi.h:460
int new_msgs
Definition mwi.h:459
const ast_string_field uniqueid
Definition mwi.h:458
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
#define AST_TEST_DEFINE(hdr)
Definition test.h:126
@ AST_TEST_PASS
Definition test.h:195
@ AST_TEST_FAIL
Definition test.h:196
@ AST_TEST_NOT_RUN
Definition test.h:194
static int subscriptions_destroy(struct subscriptions *subs)
Definition test_mwi.c:127
static int num_to_mailbox(char *mailbox, size_t size, size_t num)
Definition test_mwi.c:54
#define MAILBOX_COUNT
Definition test_mwi.c:36
static int publishers_create(struct publishers *pubs)
Definition test_mwi.c:215
static int mailbox_to_num(const char *mailbox, size_t *num)
Definition test_mwi.c:64
static int expect_zero
Definition test_mwi.c:52
static void mwi_type_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
Definition test_mwi.c:122
static size_t sum_total
Definition test_mwi.c:46
struct ast_mwi_observer mwi_observer
Definition test_mwi.c:117
static int publishers_destroy(struct publishers *pubs)
Definition test_mwi.c:190
#define test_category
Definition test_mwi.c:33
#define MAILBOX_SIZE
Definition test_mwi.c:37
static void handle_validate(const char *mailbox, struct ast_mwi_subscriber *sub)
Definition test_mwi.c:106
static int load_module(void)
Definition test_mwi.c:401
static size_t running_total
Definition test_mwi.c:49
static int unload_module(void)
Definition test_mwi.c:393
static int validate_data(struct ast_mwi_state *mwi_state)
Definition test_mwi.c:83
#define MAILBOX_PREFIX
Definition test_mwi.c:35
static int subscriptions_create(struct subscriptions *subs)
Definition test_mwi.c:145
static int explicit_publish_cb(struct ast_mwi_state *mwi_state, void *data)
Definition test_mwi.c:273
static int implicit_publish_cb(struct ast_mwi_state *mwi_state, void *data)
Definition test_mwi.c:254
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition vector.h:185
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition vector.h:124
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition vector.h:267
#define AST_VECTOR_CALLBACK_VOID(vec, callback,...)
Execute a callback on every element in a vector disregarding callback return.
Definition vector.h:873
#define AST_VECTOR(name, type)
Define a vector structure.
Definition vector.h:44
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition vector.h:691