Asterisk - The Open Source Telephony Project GIT-master-f36a736
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
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 */
206 return -1;
207 }
208
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
228 break;
229 }
230
231 /* Create the MWI publisher */
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
static int tmp()
Definition: bt_open.c:389
Conversion utility functions.
int ast_str_to_umax(const char *str, uintmax_t *res)
Convert the given string to an unsigned max size integer.
Definition: conversions.c:119
#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
def info(msg)
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124
struct stasis_forward * sub
Definition: res_corosync.c:240
#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
Definition: ast_expr2.c:325
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_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
AST_TEST_DEFINE(implicit_publish)
Definition: test_mwi.c:333
#define test_category
Definition: test_mwi.c:33
#define MAILBOX_SIZE
Definition: test_mwi.c:37
static int publish(on_mwi_state cb, void *user_data)
Definition: test_mwi.c:306
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:174
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
#define AST_VECTOR_CALLBACK_VOID(vec, callback,...)
Execute a callback on every element in a vector disregarding callback return.
Definition: vector.h:862
#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:680